├── BspZipGUI
├── icon.ico
├── App.config
├── Properties
│ ├── Settings.settings
│ ├── Settings.Designer.cs
│ ├── AssemblyInfo.cs
│ ├── Resources.Designer.cs
│ └── Resources.resx
├── App.xaml.cs
├── Models
│ ├── LogText.cs
│ └── Abstract
│ │ ├── StringWrapper.cs
│ │ └── StringBuilderWrapper.cs
├── Tool
│ ├── Execute
│ │ ├── Repack.cs
│ │ ├── Extract.cs
│ │ ├── Cubemaps.cs
│ │ ├── Bspzip.cs
│ │ ├── Pack.cs
│ │ └── FilePack.cs
│ ├── Utils
│ │ ├── Constants.cs
│ │ ├── XmlUtils.cs
│ │ ├── FunctionalException.cs
│ │ └── FileUtils.cs
│ └── Xml
│ │ └── ToolSettings.cs
├── settings.xml
├── settings_backup.txt
├── BspZipGUI.csproj
├── App.xaml
└── MainWindow.xaml
├── Images
├── LogsEnd.jpg
├── LogsMenu.jpg
├── MainMenu.jpg
├── ExtractMenu.jpg
├── MainMenuNew.jpg
├── RepackLogs.jpg
├── RepackMenu.jpg
├── CubemapsMenu.jpg
├── MainMenuNew2.jpg
├── MainMenuNew3.jpg
├── MultiPackLogs.jpg
├── MultiPackMenu.jpg
├── SettingsMenu.jpg
├── MAX_PATH_Warning.jpg
├── ExampleCustomFolder.jpg
├── SettingsWhitelist.jpg
├── SettingsCustomFolder.jpg
└── SettingsMultiCustomFolder.jpg
├── .editorconfig
├── BspZipGUI.sln
├── README.md
└── .gitignore
/BspZipGUI/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Moltard/BspZipGUI/HEAD/BspZipGUI/icon.ico
--------------------------------------------------------------------------------
/Images/LogsEnd.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Moltard/BspZipGUI/HEAD/Images/LogsEnd.jpg
--------------------------------------------------------------------------------
/Images/LogsMenu.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Moltard/BspZipGUI/HEAD/Images/LogsMenu.jpg
--------------------------------------------------------------------------------
/Images/MainMenu.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Moltard/BspZipGUI/HEAD/Images/MainMenu.jpg
--------------------------------------------------------------------------------
/Images/ExtractMenu.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Moltard/BspZipGUI/HEAD/Images/ExtractMenu.jpg
--------------------------------------------------------------------------------
/Images/MainMenuNew.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Moltard/BspZipGUI/HEAD/Images/MainMenuNew.jpg
--------------------------------------------------------------------------------
/Images/RepackLogs.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Moltard/BspZipGUI/HEAD/Images/RepackLogs.jpg
--------------------------------------------------------------------------------
/Images/RepackMenu.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Moltard/BspZipGUI/HEAD/Images/RepackMenu.jpg
--------------------------------------------------------------------------------
/Images/CubemapsMenu.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Moltard/BspZipGUI/HEAD/Images/CubemapsMenu.jpg
--------------------------------------------------------------------------------
/Images/MainMenuNew2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Moltard/BspZipGUI/HEAD/Images/MainMenuNew2.jpg
--------------------------------------------------------------------------------
/Images/MainMenuNew3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Moltard/BspZipGUI/HEAD/Images/MainMenuNew3.jpg
--------------------------------------------------------------------------------
/Images/MultiPackLogs.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Moltard/BspZipGUI/HEAD/Images/MultiPackLogs.jpg
--------------------------------------------------------------------------------
/Images/MultiPackMenu.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Moltard/BspZipGUI/HEAD/Images/MultiPackMenu.jpg
--------------------------------------------------------------------------------
/Images/SettingsMenu.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Moltard/BspZipGUI/HEAD/Images/SettingsMenu.jpg
--------------------------------------------------------------------------------
/Images/MAX_PATH_Warning.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Moltard/BspZipGUI/HEAD/Images/MAX_PATH_Warning.jpg
--------------------------------------------------------------------------------
/Images/ExampleCustomFolder.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Moltard/BspZipGUI/HEAD/Images/ExampleCustomFolder.jpg
--------------------------------------------------------------------------------
/Images/SettingsWhitelist.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Moltard/BspZipGUI/HEAD/Images/SettingsWhitelist.jpg
--------------------------------------------------------------------------------
/Images/SettingsCustomFolder.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Moltard/BspZipGUI/HEAD/Images/SettingsCustomFolder.jpg
--------------------------------------------------------------------------------
/Images/SettingsMultiCustomFolder.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Moltard/BspZipGUI/HEAD/Images/SettingsMultiCustomFolder.jpg
--------------------------------------------------------------------------------
/BspZipGUI/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/BspZipGUI/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/BspZipGUI/App.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Configuration;
4 | using System.Data;
5 | using System.Linq;
6 | using System.Threading.Tasks;
7 | using System.Windows;
8 |
9 | namespace BspZipGUI
10 | {
11 | ///
12 | /// Logique d'interaction pour App.xaml
13 | ///
14 | public partial class App : Application
15 | {
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | [*.cs]
2 |
3 | # IDE0058: La valeur d'expression n'est jamais utilisée
4 | dotnet_diagnostic.IDE0058.severity = none
5 |
6 | # IDE0046: Convertir en expression conditionnelle
7 | dotnet_diagnostic.IDE0046.severity = none
8 |
9 | # IDE0045: Convertir en expression conditionnelle
10 | dotnet_style_prefer_conditional_expression_over_assignment = false
11 |
12 | # IDE0010: Ajouter les instructions case manquantes
13 | dotnet_diagnostic.IDE0010.severity = none
14 |
--------------------------------------------------------------------------------
/BspZipGUI/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace BspZipGUI.Properties
12 | {
13 |
14 |
15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
18 | {
19 |
20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
21 |
22 | public static Settings Default
23 | {
24 | get
25 | {
26 | return defaultInstance;
27 | }
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/BspZipGUI/Models/LogText.cs:
--------------------------------------------------------------------------------
1 | using BspZipGUI.Models.Abstract;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.ComponentModel;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace BspZipGUI.Models
10 | {
11 |
12 | ///
13 | /// Store the logs and update the GUI automatically
14 | ///
15 | public class LogText : StringWrapper
16 | {
17 |
18 | #region Attributes
19 |
20 | public string Logs
21 | {
22 | get => text;
23 | set
24 | {
25 | if (text != value)
26 | {
27 | text = value;
28 | NotifyPropertyChanged();
29 | }
30 | }
31 | }
32 |
33 | #endregion
34 |
35 | #region Constructor
36 |
37 | public LogText() : base() { }
38 |
39 | #endregion
40 |
41 | #region INotifyPropertyChanged
42 |
43 | public override event PropertyChangedEventHandler PropertyChanged;
44 |
45 | public override void NotifyPropertyChanged()
46 | {
47 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Logs"));
48 | }
49 |
50 | #endregion
51 |
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/BspZipGUI.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.31613.86
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BspZipGUI", "BspZipGUI\BspZipGUI.csproj", "{0C5AD6ED-D712-4784-A6F0-259E7EAF38A3}"
7 | EndProject
8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{5B835E84-E09F-4DEA-A8BB-38F4CE6B0F1C}"
9 | ProjectSection(SolutionItems) = preProject
10 | .editorconfig = .editorconfig
11 | EndProjectSection
12 | EndProject
13 | Global
14 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
15 | Debug|Any CPU = Debug|Any CPU
16 | Release|Any CPU = Release|Any CPU
17 | EndGlobalSection
18 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
19 | {0C5AD6ED-D712-4784-A6F0-259E7EAF38A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
20 | {0C5AD6ED-D712-4784-A6F0-259E7EAF38A3}.Debug|Any CPU.Build.0 = Debug|Any CPU
21 | {0C5AD6ED-D712-4784-A6F0-259E7EAF38A3}.Release|Any CPU.ActiveCfg = Release|Any CPU
22 | {0C5AD6ED-D712-4784-A6F0-259E7EAF38A3}.Release|Any CPU.Build.0 = Release|Any CPU
23 | EndGlobalSection
24 | GlobalSection(SolutionProperties) = preSolution
25 | HideSolutionNode = FALSE
26 | EndGlobalSection
27 | GlobalSection(ExtensibilityGlobals) = postSolution
28 | SolutionGuid = {55D6D993-9364-40B3-AD50-ACACE78FE95C}
29 | EndGlobalSection
30 | EndGlobal
31 |
--------------------------------------------------------------------------------
/BspZipGUI/Models/Abstract/StringWrapper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace BspZipGUI.Models.Abstract
9 | {
10 |
11 | ///
12 | /// Wrapper for String that update the GUI
13 | ///
14 | public abstract class StringWrapper : INotifyPropertyChanged
15 | {
16 | #region Attributes
17 |
18 | protected string text;
19 |
20 | #endregion
21 |
22 | #region Constructor
23 |
24 | public StringWrapper()
25 | {
26 | Clear();
27 | }
28 |
29 | #endregion
30 |
31 | #region Methods
32 |
33 | public void Append(string str)
34 | {
35 | text += str;
36 | NotifyPropertyChanged();
37 | }
38 | public void AppendLine()
39 | {
40 | text += "\n";
41 | NotifyPropertyChanged();
42 | }
43 | public void AppendLine(string str)
44 | {
45 | text += str + "\n";
46 | NotifyPropertyChanged();
47 | }
48 | public void Clear()
49 | {
50 | text = string.Empty;
51 | NotifyPropertyChanged();
52 | }
53 |
54 | #endregion
55 |
56 | #region INotifyPropertyChanged
57 |
58 | public abstract event PropertyChangedEventHandler PropertyChanged;
59 |
60 | public abstract void NotifyPropertyChanged();
61 |
62 | #endregion
63 |
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/BspZipGUI/Models/Abstract/StringBuilderWrapper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace BspZipGUI.Models.Abstract
9 | {
10 | ///
11 | /// Wrapper for StringBuilder that update the GUI
12 | ///
13 | public abstract class StringBuilderWrapper : INotifyPropertyChanged
14 | {
15 | #region Attributes
16 |
17 | private readonly StringBuilder _sb;
18 |
19 | /* public string Text
20 | {
21 | get => _sb.ToString();
22 | set => AppendLine(value);
23 | }*/
24 |
25 | #endregion
26 |
27 | #region Constructor
28 |
29 | public StringBuilderWrapper()
30 | {
31 | _sb = new StringBuilder();
32 | }
33 |
34 | public StringBuilderWrapper(StringBuilder sb)
35 | {
36 | _sb = sb;
37 | }
38 |
39 | #endregion
40 |
41 | #region Methods
42 |
43 | public void Append(string str)
44 | {
45 | _sb.Append(str);
46 | NotifyPropertyChanged();
47 | }
48 | public void AppendLine(string str)
49 | {
50 | _sb.AppendLine(str);
51 | NotifyPropertyChanged();
52 | }
53 | public void Clear()
54 | {
55 | _sb.Clear();
56 | NotifyPropertyChanged();
57 | }
58 |
59 | #endregion
60 |
61 | #region INotifyPropertyChanged
62 |
63 | public abstract event PropertyChangedEventHandler PropertyChanged;
64 |
65 | public abstract void NotifyPropertyChanged();
66 |
67 | #endregion INotifyPropertyChanged
68 | }
69 |
70 | }
71 |
--------------------------------------------------------------------------------
/BspZipGUI/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Resources;
3 | using System.Runtime.CompilerServices;
4 | using System.Runtime.InteropServices;
5 | using System.Windows;
6 |
7 | // Les informations générales relatives à un assembly dépendent de
8 | // l'ensemble d'attributs suivant. Changez les valeurs de ces attributs pour modifier les informations
9 | // associées à un assembly.
10 | [assembly: AssemblyTitle("BspZipGUI")]
11 | [assembly: AssemblyDescription("")]
12 | [assembly: AssemblyConfiguration("")]
13 | [assembly: AssemblyCompany("")]
14 | [assembly: AssemblyProduct("BspZipGUI")]
15 | [assembly: AssemblyCopyright("Copyright © 2020")]
16 | [assembly: AssemblyTrademark("")]
17 | [assembly: AssemblyCulture("")]
18 |
19 | // L'affectation de la valeur false à ComVisible rend les types invisibles dans cet assembly
20 | // aux composants COM. Si vous devez accéder à un type dans cet assembly à partir de
21 | // COM, affectez la valeur true à l'attribut ComVisible sur ce type.
22 | [assembly: ComVisible(false)]
23 |
24 | //Pour commencer à générer des applications localisables, définissez
25 | //CultureUtiliséePourCoder dans votre fichier .csproj
26 | //dans . Par exemple, si vous utilisez le français
27 | //dans vos fichiers sources, définissez à fr-FR. Puis, supprimez les marques de commentaire de
28 | //l'attribut NeutralResourceLanguage ci-dessous. Mettez à jour "fr-FR" dans
29 | //la ligne ci-après pour qu'elle corresponde au paramètre UICulture du fichier projet.
30 |
31 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
32 |
33 |
34 | [assembly: ThemeInfo(
35 | ResourceDictionaryLocation.None, //où se trouvent les dictionnaires de ressources spécifiques à un thème
36 | //(utilisé si une ressource est introuvable dans la page,
37 | // ou dictionnaires de ressources de l'application)
38 | ResourceDictionaryLocation.SourceAssembly //où se trouve le dictionnaire de ressources générique
39 | //(utilisé si une ressource est introuvable dans la page,
40 | // dans l'application ou dans l'un des dictionnaires de ressources spécifiques à un thème)
41 | )]
42 |
43 |
44 | // Les informations de version pour un assembly se composent des quatre valeurs suivantes :
45 | //
46 | // Version principale
47 | // Version secondaire
48 | // Numéro de build
49 | // Révision
50 | //
51 | // Vous pouvez spécifier toutes les valeurs ou indiquer les numéros de build et de révision par défaut
52 | // en utilisant '*', comme indiqué ci-dessous :
53 | // [assembly: AssemblyVersion("1.0.*")]
54 | [assembly: AssemblyVersion("1.0.0.0")]
55 | [assembly: AssemblyFileVersion("1.0.0.0")]
56 |
--------------------------------------------------------------------------------
/BspZipGUI/Tool/Execute/Repack.cs:
--------------------------------------------------------------------------------
1 | using BspZipGUI.Models;
2 | using BspZipGUI.Tool.Utils;
3 | using BspZipGUI.Tool.Xml;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Diagnostics;
7 | using System.Linq;
8 | using System.Text;
9 | using System.Threading.Tasks;
10 |
11 | namespace BspZipGUI.Tool.Execute
12 | {
13 | internal class Repack : Bspzip
14 | {
15 |
16 | #region Attributes
17 |
18 | ///
19 | /// If the goal is to Compress or Uncompress the BSP
20 | ///
21 | private readonly bool isCompress;
22 |
23 | #endregion
24 |
25 | #region Constructor
26 |
27 | public Repack(ToolSettings toolSettings, GameConfig game, string bspPath, LogText logsOutput, bool isCompress) :
28 | base(toolSettings, game, bspPath, logsOutput)
29 | {
30 | this.isCompress = isCompress;
31 | }
32 |
33 | #endregion
34 |
35 | #region Methods
36 |
37 | ///
38 | /// Start the repacking for the current options
39 | ///
40 | /// Error when creating the bsp backup
41 | /// Error during bspzip execution
42 | public override void Start()
43 | {
44 | UpdateSettings();
45 | logsOutput.AppendLine();
46 | try
47 | {
48 | CreateBackupBsp();
49 | }
50 | catch (Exception ex)
51 | {
52 | throw new BspBackupCreationException(MessageConstants.MessageCopyBspFail, ex);
53 | }
54 | try
55 | {
56 | StartProcess();
57 | }
58 | catch (Exception ex)
59 | {
60 | throw new BspZipExecutionException(MessageConstants.MessageBspzipFail, ex);
61 | }
62 | }
63 |
64 | ///
65 | /// Return the arguments to launch bspzip.exe, to repack or un-repack a BSP
66 | ///
67 | protected override string GetProcessArguments()
68 | {
69 | // bspzip -repack [ -compress ] ""
70 | StringBuilder sb = new StringBuilder("-repack ");
71 | if (isCompress)
72 | {
73 | sb.Append("-compress ");
74 | }
75 | sb.Append($"\"{bspPath}\"");
76 | return sb.ToString();
77 | }
78 |
79 | ///
80 | ///
81 | ///
82 | protected override void UpdateSettings()
83 | {
84 | toolSettings.LastBsp = bspPath;
85 | toolSettings.LastGame = game.Name;
86 | SaveSettings();
87 | }
88 |
89 | #endregion
90 |
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/BspZipGUI/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // Ce code a été généré par un outil.
4 | // Version du runtime :4.0.30319.42000
5 | //
6 | // Les modifications apportées à ce fichier peuvent provoquer un comportement incorrect et seront perdues si
7 | // le code est régénéré.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace BspZipGUI.Properties
12 | {
13 |
14 |
15 | ///
16 | /// Une classe de ressource fortement typée destinée, entre autres, à la consultation des chaînes localisées.
17 | ///
18 | // Cette classe a été générée automatiquement par la classe StronglyTypedResourceBuilder
19 | // à l'aide d'un outil, tel que ResGen ou Visual Studio.
20 | // Pour ajouter ou supprimer un membre, modifiez votre fichier .ResX, puis réexécutez ResGen
21 | // avec l'option /str ou régénérez votre projet VS.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources
26 | {
27 |
28 | private static global::System.Resources.ResourceManager resourceMan;
29 |
30 | private static global::System.Globalization.CultureInfo resourceCulture;
31 |
32 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
33 | internal Resources()
34 | {
35 | }
36 |
37 | ///
38 | /// Retourne l'instance ResourceManager mise en cache utilisée par cette classe.
39 | ///
40 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
41 | internal static global::System.Resources.ResourceManager ResourceManager
42 | {
43 | get
44 | {
45 | if ((resourceMan == null))
46 | {
47 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("BspZipGUI.Properties.Resources", typeof(Resources).Assembly);
48 | resourceMan = temp;
49 | }
50 | return resourceMan;
51 | }
52 | }
53 |
54 | ///
55 | /// Remplace la propriété CurrentUICulture du thread actuel pour toutes
56 | /// les recherches de ressources à l'aide de cette classe de ressource fortement typée.
57 | ///
58 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
59 | internal static global::System.Globalization.CultureInfo Culture
60 | {
61 | get
62 | {
63 | return resourceCulture;
64 | }
65 | set
66 | {
67 | resourceCulture = value;
68 | }
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/BspZipGUI/Tool/Execute/Extract.cs:
--------------------------------------------------------------------------------
1 | using BspZipGUI.Models;
2 | using BspZipGUI.Tool.Utils;
3 | using BspZipGUI.Tool.Xml;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Diagnostics;
7 | using System.Linq;
8 | using System.Text;
9 | using System.Threading.Tasks;
10 |
11 | namespace BspZipGUI.Tool.Execute
12 | {
13 | internal class Extract : Bspzip
14 | {
15 |
16 | #region Attributes
17 |
18 | ///
19 | /// True if extract to a zip file, false if extract to a folder
20 | ///
21 | private readonly bool isExtractToZip;
22 |
23 | ///
24 | /// Name of the zip file or folder path
25 | ///
26 | private readonly string extractPath;
27 |
28 | #endregion
29 |
30 | #region Constructor
31 |
32 | public Extract(ToolSettings toolSettings, GameConfig game, string bspPath, LogText logsOutput, bool isExtractToZip, string extractPath) :
33 | base(toolSettings, game, bspPath, logsOutput)
34 | {
35 | this.isExtractToZip = isExtractToZip;
36 | this.extractPath = extractPath;
37 | }
38 |
39 | #endregion
40 |
41 | #region Methods
42 |
43 | ///
44 | /// Extract the map content into a zip file or folder
45 | ///
46 | /// Error during bspzip execution
47 | public override void Start()
48 | {
49 | UpdateSettings();
50 | try
51 | {
52 | StartProcess();
53 | }
54 | catch (Exception ex)
55 | {
56 | throw new BspZipExecutionException(MessageConstants.MessageBspzipFail, ex);
57 | }
58 | }
59 |
60 | ///
61 | /// Return the arguments to launch bspzip.exe, to extract or delete cubemaps from a BSP
62 | ///
63 | ///
64 | protected override string GetProcessArguments()
65 | {
66 | // bspzip -extract "" ""
67 | // bspzip -extractfiles "" ""
68 | StringBuilder sb;
69 | if (isExtractToZip)
70 | {
71 | sb = new StringBuilder("-extract ")
72 | .Append($"\"{bspPath}\" ")
73 | .Append($"\"{extractPath}\"");
74 | }
75 | else
76 | {
77 | sb = new StringBuilder("-extractfiles ")
78 | .Append($"\"{bspPath}\" ")
79 | .Append($"\"{extractPath}\"");
80 | }
81 | return sb.ToString();
82 | }
83 |
84 | ///
85 | ///
86 | ///
87 | protected override void UpdateSettings()
88 | {
89 | toolSettings.LastBsp = bspPath;
90 | toolSettings.LastGame = game.Name;
91 | if (!isExtractToZip)
92 | {
93 | toolSettings.LastExtractDirectory = extractPath;
94 | }
95 | SaveSettings();
96 | }
97 |
98 |
99 | #endregion
100 |
101 | }
102 |
103 |
104 |
105 |
106 | }
107 |
--------------------------------------------------------------------------------
/BspZipGUI/Tool/Execute/Cubemaps.cs:
--------------------------------------------------------------------------------
1 | using BspZipGUI.Models;
2 | using BspZipGUI.Tool.Utils;
3 | using BspZipGUI.Tool.Xml;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Diagnostics;
7 | using System.Linq;
8 | using System.Text;
9 | using System.Threading.Tasks;
10 |
11 | namespace BspZipGUI.Tool.Execute
12 | {
13 | internal class Cubemaps : Bspzip
14 | {
15 |
16 | #region Attributes
17 |
18 | ///
19 | /// True if extract cubemaps, false if delete cubemaps
20 | ///
21 | private readonly bool isExtractCubemap;
22 |
23 | ///
24 | /// Path for the cubemap extraction
25 | ///
26 | private readonly string extractPath;
27 |
28 | #endregion
29 |
30 | #region Constructor
31 |
32 | public Cubemaps(ToolSettings toolSettings, GameConfig game, string bspPath, LogText logsOutput, bool isExtractCubemap, string extractPath) :
33 | base(toolSettings, game, bspPath, logsOutput)
34 | {
35 | this.isExtractCubemap = isExtractCubemap;
36 | this.extractPath = extractPath;
37 | }
38 |
39 | #endregion
40 |
41 | #region Methods
42 |
43 | ///
44 | /// Extract or Delete cubemaps
45 | ///
46 | /// Error during bspzip execution
47 | public override void Start()
48 | {
49 | UpdateSettings();
50 | if (!isExtractCubemap)
51 | {
52 | // If delete cubemaps, we make a backup of the bsp
53 | try
54 | {
55 | CreateBackupBsp();
56 | }
57 | catch (Exception ex)
58 | {
59 | logsOutput.AppendLine();
60 | throw new BspBackupCreationException(MessageConstants.MessageCopyBspFail, ex);
61 | }
62 | }
63 | try
64 | {
65 | StartProcess();
66 | }
67 | catch (Exception ex)
68 | {
69 | logsOutput.AppendLine();
70 | throw new BspZipExecutionException(MessageConstants.MessageBspzipFail, ex);
71 | }
72 | }
73 |
74 | ///
75 | /// Return the arguments to launch bspzip.exe, to extract or delete cubemaps from a BSP
76 | ///
77 | ///
78 | protected override string GetProcessArguments()
79 | {
80 | // bspzip -extractcubemaps "" ""
81 | // bspzip -deletecubemaps ""
82 | StringBuilder sb;
83 | if (isExtractCubemap)
84 | {
85 | sb = new StringBuilder("-extractcubemaps ")
86 | .Append($"\"{bspPath}\" ")
87 | .Append($"\"{extractPath}\"");
88 | }
89 | else
90 | {
91 | sb = new StringBuilder("-deletecubemaps ")
92 | .Append($"\"{bspPath}\"");
93 | }
94 | return sb.ToString();
95 | }
96 |
97 | ///
98 | ///
99 | ///
100 | protected override void UpdateSettings()
101 | {
102 | toolSettings.LastBsp = bspPath;
103 | toolSettings.LastGame = game.Name;
104 | if (isExtractCubemap)
105 | {
106 | toolSettings.LastExtractDirectory = extractPath;
107 | }
108 | SaveSettings();
109 | }
110 |
111 | #endregion
112 |
113 | }
114 |
115 |
116 |
117 |
118 | }
119 |
--------------------------------------------------------------------------------
/BspZipGUI/settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Counter-Strike: Global Offensive
5 | My Current Project
6 |
7 | False
8 |
9 |
10 | Counter-Strike: Source
11 | C:\Program Files (x86)\Steam\steamapps\common\Counter-Strike Source\bin\bspzip.exe
12 | C:\Program Files (x86)\Steam\steamapps\common\Counter-Strike Source\cstrike\gameinfo.txt
13 |
14 |
15 | Counter-Strike: Global Offensive
16 | C:\Program Files (x86)\Steam\steamapps\common\Counter-Strike Global Offensive\bin\bspzip.exe
17 | C:\Program Files (x86)\Steam\steamapps\common\Counter-Strike Global Offensive\csgo\gameinfo.txt
18 |
19 |
20 | Half-Life 2
21 | C:\Program Files (x86)\Steam\steamapps\common\Half-Life 2\bin\bspzip.exe
22 | C:\Program Files (x86)\Steam\steamapps\common\Half-Life 2\hl2\gameinfo.txt
23 |
24 |
25 |
26 |
30 |
31 |
32 |
33 | cfg
34 |
35 | .cfg
36 | .txt
37 |
38 |
39 |
40 | maps
41 |
42 | .txt
43 | .kv
44 |
45 |
46 |
47 | materials
48 |
49 | .vmt
50 | .vtf
51 |
52 |
53 |
54 | models
55 |
56 | .mdl
57 | .phy
58 | .vtx
59 | .vvd
60 | .ani
61 |
62 |
63 |
64 | particles
65 |
66 | .pcf
67 | .txt
68 |
69 |
70 |
71 | resource
72 |
73 | .dds
74 | .txt
75 |
76 |
77 |
78 | scripts
79 |
80 | .lua
81 | .nut
82 | .txt
83 |
84 |
85 |
86 | sound
87 |
88 | .mp3
89 | .txt
90 | .wav
91 |
92 |
93 |
94 | materials/correction
95 |
96 | .raw
97 |
98 |
99 |
100 | materials/panorama/images/map_icons/screenshots
101 |
102 | .png
103 |
104 |
105 |
106 |
107 |
113 |
114 |
115 |
--------------------------------------------------------------------------------
/BspZipGUI/settings_backup.txt:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Counter-Strike: Global Offensive
5 | My Current Project
6 |
7 | False
8 |
9 |
10 | Counter-Strike: Source
11 | C:\Program Files (x86)\Steam\steamapps\common\Counter-Strike Source\bin\bspzip.exe
12 | C:\Program Files (x86)\Steam\steamapps\common\Counter-Strike Source\cstrike\gameinfo.txt
13 |
14 |
15 | Counter-Strike: Global Offensive
16 | C:\Program Files (x86)\Steam\steamapps\common\Counter-Strike Global Offensive\bin\bspzip.exe
17 | C:\Program Files (x86)\Steam\steamapps\common\Counter-Strike Global Offensive\csgo\gameinfo.txt
18 |
19 |
20 | Half-Life 2
21 | C:\Program Files (x86)\Steam\steamapps\common\Half-Life 2\bin\bspzip.exe
22 | C:\Program Files (x86)\Steam\steamapps\common\Half-Life 2\hl2\gameinfo.txt
23 |
24 |
25 |
26 |
30 |
31 |
32 |
33 | cfg
34 |
35 | .cfg
36 | .txt
37 |
38 |
39 |
40 | maps
41 |
42 | .txt
43 | .kv
44 |
45 |
46 |
47 | materials
48 |
49 | .vmt
50 | .vtf
51 |
52 |
53 |
54 | models
55 |
56 | .mdl
57 | .phy
58 | .vtx
59 | .vvd
60 | .ani
61 |
62 |
63 |
64 | particles
65 |
66 | .pcf
67 | .txt
68 |
69 |
70 |
71 | resource
72 |
73 | .dds
74 | .txt
75 |
76 |
77 |
78 | scripts
79 |
80 | .lua
81 | .nut
82 | .txt
83 |
84 |
85 |
86 | sound
87 |
88 | .mp3
89 | .txt
90 | .wav
91 |
92 |
93 |
94 | materials/correction
95 |
96 | .raw
97 |
98 |
99 |
100 | materials/panorama/images/map_icons/screenshots
101 |
102 | .png
103 |
104 |
105 |
106 |
107 |
113 |
114 |
115 |
--------------------------------------------------------------------------------
/BspZipGUI/Tool/Utils/Constants.cs:
--------------------------------------------------------------------------------
1 | namespace BspZipGUI.Tool.Utils
2 | {
3 | ///
4 | /// Class containing constants used in the app
5 | ///
6 | internal static class Constants
7 | {
8 |
9 | #region Constants
10 |
11 | ///
12 | /// The max path length correctly supported by Windows.
13 | /// Trying to pack a file that use a path longer than this will break the bspzip.exe process itself.
14 | /// It won't pack any file after encountering the limit.
15 | /// This will only be used to show a warning to the user after the execution.
16 | ///
17 | public const int MAX_PATH = 260;
18 |
19 | public const string ExtensionBsp = ".bsp";
20 | public const string ExtensionExe = ".exe";
21 | public const string ExtensionTxt = ".txt";
22 | public const string ExtensionZip = ".zip";
23 |
24 | public const string BspZipFile = "bspzip.exe";
25 | public const string GameinfoFile = "gameinfo.txt";
26 |
27 | ///
28 | /// The name of the text file listing all files to pack
29 | ///
30 | public const string FilesListText = "filesList.txt";
31 |
32 | public const char Slash = '/';
33 | public const char Backslash = '\\';
34 |
35 | #endregion
36 |
37 | }
38 |
39 | ///
40 | /// Class containing constants message used in the GUI
41 | ///
42 | internal static class MessageConstants
43 | {
44 |
45 | #region Constants
46 |
47 | //public const string MessageToolNotWork = "The tool will not work correctly";
48 |
49 | public const string MessageSettingsSaveSuccess = "Saved settings to settings.xml";
50 | public const string MessageSettingsSaveError = "Error trying to save settings";
51 | public const string MessageSettingsCreateError = "Error creating settings.xml";
52 | public const string MessageSettingsReadError = "Error while reading the settings";
53 | public const string MessageSettingsUseDefault = "Trying to use the default settings instead";
54 | public const string MessageSettingsDefaultReadError = "Error while reading the default settings";
55 | public const string MessageSettingsUseEmpty = "Generating empty settings";
56 |
57 | public const string MessageFileNotBsp = "The file is not .bsp";
58 | public const string MessageBspFileNotFound = "The .bsp file doesn't exist";
59 | public const string MessageDirectoryNotFound = "The directory doesn't exist";
60 | public const string MessageCustomFolderNotFound = "The Custom Folder doesn't exist";
61 | public const string MessageMultiCustomFolderEmpty = "The list of Custom Folders is empty";
62 | public const string MessageMultiCustomFolderNotFound = "One or multiple Custom Folder(s) don't exist";
63 | public const string MessageSimpleMultiCustomFolderNotSelected = "Invalid state: No Custom Folder(s) were selected";
64 | public const string MessageMultiCustomFolderSettingsNotSelected = "No Custom Folders selected";
65 | public const string MessageCustomFolderInvalid = "Invalid Custom Folder selected";
66 | public const string MessageGameNotFound = "Can't find the specified bspzip.exe and/or gameinfo.txt";
67 | public const string MessageGameInvalid = "Invalid Game selected";
68 |
69 | public const string MessageBspPacking = "Bsp packing in progress...";
70 | public const string MessageBspRepackCompress = "Bsp compressing in progress...";
71 | public const string MessageBspRepackDecompress = "Bsp decompressing in progress...";
72 | public const string MessageBspExtractFile = "Bsp extraction in progress...";
73 | public const string MessageBspExtractCubemaps = "Cubemaps extraction in progress...";
74 | public const string MessageBspDeleteCubemaps = "Cubemaps deletion in progress...";
75 |
76 | public const string MessageSeeLogs = "\nSee logs for more details";
77 |
78 | public const string MessageBspzipSuccess = "Success";
79 | public const string MessageBspzipFail = "Error: bspzip.exe process ended unexpectedly";
80 | public const string MessageCopyBspFail = "Error: Couldn't make a copy of the BSP";
81 | public const string MessageListFilesNotFound = "Error: Couldn't find the list of files to pack";
82 | public const string MessageListFilesFail = "Error: Couldn't create the list of files to pack";
83 | public const string MessageMaxPathSizeWarning = "One or more file(s) path(s) are longer than 260 characters (MAX_PATH)";
84 | public const string MessageMaxPathSizeSuggestion = "Suggestion: Move your custom directory to a shorter path";
85 | public const string MessageBspzipPackingWarning = "Warning: bspzip.exe may not have packed all the files correctly";
86 |
87 | public const string MessageWhitelistWarning = "You unchecked \"Use Directory Whitelist\", it will pack every single files from the directory " +
88 | "and its subdirectories.\nAre you really sure ?\n(Be careful not to use a path like C:\\)";
89 |
90 | #endregion
91 |
92 | }
93 |
94 | }
95 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # BspZipGUI
2 | A clean GUI tool that use Valve's BSPZIP command line utility. It is used to embed a folder with custom files (materials, models, sound,..) into a BSP file.
3 |
4 |
5 |
6 | You can also repack a map to compress (or decompress it).
7 |
8 | It can be used for any Source Engine game that provide a bspzip.exe.
9 |
10 | This tool idea is based on [Geotavros's BspZipGui](https://github.com/geotavros/BspZipGui) .
11 |
12 | ## Download
13 |
14 | [BspZipGUI v3.0](https://github.com/Moltard/BspZipGUI/releases/latest)
15 |
16 | ## How to use - Bsp Packer
17 |
18 | Select a game you defined (3 are setup per default), a custom folder you defined and load a BSP.
19 |
20 | Check 'Use Directory Whitelist' (recommended) to only pack files from whitelisted directories (see Settings).
21 |
22 |
23 |
24 | Press Pack Bsp.
25 |
26 |
27 |
28 |
29 | ## How to use - Bsp Multi Packer
30 |
31 | Select a game you defined (3 are setup per default), a 'multi custom' folder you defined and load a BSP.
32 |
33 | **A multi custom folder contains one or more custom folder. The content of all those folders will be packed into the map**
34 |
35 | Check 'Use Directory Whitelist' (recommended) to only pack files from whitelisted directories (see Settings).
36 |
37 |
38 |
39 | Press Pack Bsp.
40 |
41 |
42 |
43 |
44 | ## How to use - Bsp Repack
45 |
46 | Select a game you defined (3 are setup per default) and load a BSP.
47 |
48 |
49 |
50 | Press Compress Bsp or Decompress Bsp.
51 |
52 |
53 |
54 | ## How to use - Bsp Extract
55 |
56 | Select a game you defined (3 are setup per default) and load a BSP.
57 |
58 |
59 |
60 | Either select a directory (drag drop possible) and click Extract to Directory, or click Extract to Zip.
61 |
62 | All packed files will be extracted to the directory/zip file.
63 |
64 |
65 | ## How to use - Bsp Cubemaps
66 |
67 | Select a game you defined (3 are setup per default) and load a BSP.
68 |
69 |
70 |
71 | Either select a directory (drag drop possible) and click Extract cubemaps, or click Delete cubemaps.
72 |
73 | /!\\ Deleting cubemaps actually delete every VTF files packed. That is how bspzip work.
74 |
75 |
76 |
77 | ## How to setup
78 |
79 | ### Games
80 |
81 | Add new 'games' configs with the 'Add...' button. Delete them with the 'Delete' button.
82 |
83 | Setup your games by loading the gameinfo.txt and bspzip.exe.
84 |
85 |
86 |
87 | ---
88 |
89 | ### Custom Folders
90 |
91 | Add new 'custom folders' configs with the 'Add...' button. Delete them with the 'Delete' button.
92 |
93 | Load the folder with the custom files that you want to embed in your map.
94 |
95 |
96 |
97 | ---
98 |
99 | ### Multi Custom Folders
100 |
101 | Add new 'multi custom folders' configs with the 'Add...' button. Delete them with the 'Delete' button.
102 |
103 | Add the folders with the custom files that you want to embed in your map, with the "Add Directory" button.
104 |
105 | Remove a folder from the list with Remove Selected.
106 |
107 | Drag and dropping is supported.
108 |
109 |
110 |
111 | ---
112 |
113 | ### Directories Whitelist
114 |
115 | Define a whitelist of subfolders and type of files (through their extensions) that can be packed.
116 |
117 |
118 |
119 | (All the subfolders you would need are already setup, but you can edit to your needs)
120 |
121 | ### Extra setting
122 |
123 | To not bloat the UI, one setting can only be changed by modifying **settings.xml**, which is the Asynchronous / Synchronous log output. When bspzip.exe is getting executed, you can either get the output of the process as it is getting executed (Async) or get all of it at once after it has finished (Sync).
124 |
125 | It doesn't really affect the execution, but you can change it if you want by editing the following line:
126 |
127 | \False\
128 |
129 | - **False** means that logs are Asynchronously displayed, which is the default behavior
130 | - **True** means that logs are Synchronously displayed
131 | - Not having the line (if you had old settings), will use Asynchronous mode and next time settings are saved, the value will be at **False**.
132 |
133 |
134 | ### MAX_PATH size limit
135 |
136 | Windows has a hardcoded limitation for file paths, which affect bspzip.exe.
137 |
138 | - [Microsoft Doc](https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation)
139 |
140 | If a file path is 260 or more characters, and is packed by bspzip.exe, it will cause issues with packing the rest of the files.
141 | Because it's not something fixable with this software, I instead added a warning if such case happens.
142 |
143 |
144 |
145 | The solution is simple and just requires you to have your custom folder in a shorter path.
146 |
147 |
148 | ### Developers
149 |
150 | - [Moltard](https://github.com/Moltard)
151 |
152 |
153 |
154 |
--------------------------------------------------------------------------------
/BspZipGUI/BspZipGUI.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {0C5AD6ED-D712-4784-A6F0-259E7EAF38A3}
8 | WinExe
9 | BspZipGUI
10 | BspZipGUI
11 | v4.6.1
12 | 512
13 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
14 | 4
15 | true
16 | true
17 |
18 |
19 | AnyCPU
20 | true
21 | full
22 | false
23 | bin\Debug\
24 | DEBUG;TRACE
25 | prompt
26 | 4
27 |
28 |
29 | AnyCPU
30 | pdbonly
31 | true
32 | bin\Release\
33 | TRACE
34 | prompt
35 | 4
36 |
37 |
38 | icon.ico
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 | 4.0
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 | MSBuild:Compile
59 | Designer
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 | MSBuild:Compile
77 | Designer
78 |
79 |
80 | App.xaml
81 | Code
82 |
83 |
84 | MainWindow.xaml
85 | Code
86 |
87 |
88 |
89 |
90 | Code
91 |
92 |
93 | True
94 | True
95 | Resources.resx
96 |
97 |
98 | True
99 | Settings.settings
100 | True
101 |
102 |
103 | ResXFileCodeGenerator
104 | Resources.Designer.cs
105 |
106 |
107 | .editorconfig
108 |
109 |
110 | SettingsSingleFileGenerator
111 | Settings.Designer.cs
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 | Designer
120 | PreserveNewest
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
--------------------------------------------------------------------------------
/BspZipGUI/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 | text/microsoft-resx
107 |
108 |
109 | 2.0
110 |
111 |
112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
113 |
114 |
115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
--------------------------------------------------------------------------------
/BspZipGUI/Tool/Utils/XmlUtils.cs:
--------------------------------------------------------------------------------
1 | using BspZipGUI.Tool.Xml;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using System.Xml.Serialization;
8 |
9 | namespace BspZipGUI.Tool.Utils
10 | {
11 | internal static class XmlUtils
12 | {
13 | #region Constants
14 |
15 | ///
16 | /// Name of the Settings file
17 | ///
18 | private const string xmlSettings = "settings.xml";
19 |
20 | ///
21 | /// Path to the default settings, stored in the App
22 | ///
23 | private const string xmlSettingsBackup = "BspZipGUI.settings_backup.txt";
24 |
25 | #endregion
26 |
27 | #region Methods
28 |
29 | ///
30 | /// Get the settings of the application by reading settings.xml
31 | ///
32 | /// If an error happens during the parsingof the file
33 | /// The initialized Settings or null if the file doesn't exist
34 | public static ToolSettings GetSettingsFromFile()
35 | {
36 | if (System.IO.File.Exists(xmlSettings))
37 | {
38 | // If settings.xml exist, we load it
39 | return DeserializeSettingsFromFile(xmlSettings);
40 | }
41 | return null;
42 | }
43 |
44 |
45 | ///
46 | /// Read and parse the given settings file
47 | ///
48 | /// Name of the file to parse
49 | /// If an error happens during the parsing
50 | /// Parsed settings
51 | private static ToolSettings DeserializeSettingsFromFile(string filename)
52 | {
53 | try
54 | {
55 | using (System.IO.StreamReader reader = new System.IO.StreamReader(filename))
56 | {
57 | XmlSerializer serializer = new XmlSerializer(typeof(ToolSettings));
58 | return (ToolSettings)serializer.Deserialize(reader);
59 | }
60 | }
61 | catch (Exception ex)
62 | {
63 | throw new SettingsSerializationException(MessageConstants.MessageSettingsReadError, ex);
64 | }
65 | }
66 |
67 | ///
68 | /// Get the default settings stored in the .exe
69 | ///
70 | /// If an error happens when reading and parsing the default settings
71 | /// Parsed settings
72 | public static ToolSettings GetSettingsFromResource()
73 | {
74 | // If it doesn't exist, we load it from the embedded ressource and recreate it
75 | string xmlText;
76 | try
77 | {
78 | xmlText = FileUtils.ReadResourceFile(xmlSettingsBackup);
79 | }
80 | catch (Exception ex)
81 | {
82 | throw new SettingsSerializationException(MessageConstants.MessageSettingsDefaultReadError, ex);
83 | }
84 | return DeserializeSettingsFromText(xmlText);
85 | }
86 |
87 |
88 | ///
89 | /// Read and parse the given string into Settings
90 | ///
91 | /// the text to parse
92 | /// If an error happens during the parsing
93 | /// Parsed settings
94 | private static ToolSettings DeserializeSettingsFromText(string xmlText)
95 | {
96 | try
97 | {
98 | using (System.IO.StringReader reader = new System.IO.StringReader(xmlText))
99 | {
100 | XmlSerializer serializer = new XmlSerializer(typeof(ToolSettings));
101 | return (ToolSettings)serializer.Deserialize(reader);
102 | }
103 | }
104 | catch (Exception ex)
105 | {
106 | throw new SettingsSerializationException(MessageConstants.MessageSettingsDefaultReadError, ex);
107 | }
108 | }
109 |
110 | ///
111 | /// Save the given settings in settings.xml
112 | ///
113 | /// The settings to save
114 | /// If an error happens during the serialization of the file
115 | /// true if successful, false if the Settings are null
116 | public static bool SerializeSettings(ToolSettings settings)
117 | {
118 | if (settings != null)
119 | {
120 | System.Xml.XmlWriterSettings xmlWritterSettings =
121 | new System.Xml.XmlWriterSettings() { Indent = true };
122 | try
123 | {
124 | using (System.IO.StreamWriter writer = new System.IO.StreamWriter(xmlSettings))
125 | using (System.Xml.XmlWriter xmlWriter = System.Xml.XmlWriter.Create(writer, xmlWritterSettings))
126 | {
127 | XmlSerializer serializer = new XmlSerializer(typeof(ToolSettings));
128 | serializer.Serialize(xmlWriter, settings);
129 | }
130 | return true;
131 | }
132 | catch (Exception ex)
133 | {
134 | throw new SettingsSerializationException(MessageConstants.MessageSettingsSaveError, ex);
135 | }
136 | }
137 | return false;
138 | }
139 |
140 | #endregion
141 |
142 | }
143 |
144 |
145 |
146 | }
147 |
--------------------------------------------------------------------------------
/BspZipGUI/Tool/Execute/Bspzip.cs:
--------------------------------------------------------------------------------
1 | using BspZipGUI.Models;
2 | using BspZipGUI.Tool.Utils;
3 | using BspZipGUI.Tool.Xml;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Diagnostics;
7 | using System.Linq;
8 | using System.Text;
9 | using System.Threading.Tasks;
10 |
11 | namespace BspZipGUI.Tool.Execute
12 | {
13 | internal abstract class Bspzip
14 | {
15 |
16 | #region Attributes
17 |
18 | ///
19 | /// The current settings of the tool
20 | ///
21 | protected readonly ToolSettings toolSettings;
22 |
23 | ///
24 | /// The game used for packing (bspzip.exe)
25 | ///
26 | protected readonly GameConfig game;
27 |
28 | ///
29 | /// The path to the BSP file
30 | ///
31 | protected readonly string bspPath;
32 |
33 | ///
34 | /// The output logs from the bspzip process
35 | ///
36 | protected readonly LogText logsOutput;
37 |
38 | ///
39 | /// Should the logs be written asynchronously or synchronously
40 | ///
41 | protected readonly bool isSyncLogsOutput;
42 |
43 | #endregion
44 |
45 | #region Constructor
46 |
47 | protected Bspzip(ToolSettings toolSettings, GameConfig game, string bspPath, LogText logsOutput)
48 | {
49 | this.toolSettings = toolSettings;
50 | this.game = game;
51 | this.bspPath = bspPath;
52 | this.logsOutput = logsOutput;
53 | isSyncLogsOutput = toolSettings.IsSyncLogs;
54 | }
55 |
56 | #endregion
57 |
58 | #region Methods
59 |
60 | ///
61 | /// Function to start bspzip.exe
62 | /// Implemented by the classes that inherit from
63 | ///
64 | public abstract void Start();
65 |
66 | ///
67 | /// Launch a process of bspzip.exe with the given arguments
68 | ///
69 | protected void StartProcess()
70 | {
71 | ProcessStartInfo startInfo = new ProcessStartInfo(game.BspZip, GetProcessArguments())
72 | {
73 | UseShellExecute = false,
74 | RedirectStandardOutput = true,
75 | RedirectStandardError = true,
76 | CreateNoWindow = true,
77 |
78 | };
79 | startInfo.EnvironmentVariables["VPROJECT"] = game.GameInfoFolder;
80 |
81 | Process p = new Process { StartInfo = startInfo };
82 |
83 | if (isSyncLogsOutput)
84 | {
85 | // Sync output
86 | p.Start();
87 | string output = p.StandardOutput.ReadToEnd();
88 | logsOutput.AppendLine(output);
89 | p.WaitForExit();
90 | }
91 | else
92 | {
93 | // Async output
94 | p.OutputDataReceived += new DataReceivedEventHandler(ProcessOutputHandler);
95 | p.ErrorDataReceived += new DataReceivedEventHandler(ProcessErrorHandler);
96 | p.Start();
97 | p.BeginOutputReadLine();
98 | p.WaitForExit();
99 | p.Close();
100 | }
101 |
102 | // To stop the output reading
103 | // p.CancelOutputRead();
104 | // p.Close()
105 |
106 |
107 | }
108 |
109 | ///
110 | /// Create a backup of the BSP
111 | ///
112 | /// Exception of any type thrown if an error happened during the file deletion/creation
113 | protected void CreateBackupBsp()
114 | {
115 | string backupBsp = bspPath + "_old";
116 | if (System.IO.File.Exists(backupBsp))
117 | {
118 | System.IO.File.Delete(backupBsp);
119 | }
120 | System.IO.File.Copy(bspPath, backupBsp);
121 | logsOutput.AppendLine($"Created a copy of \"{bspPath}\" \n=> \"{backupBsp}\"\n");
122 | }
123 |
124 | ///
125 | /// Get the arguments used to launch bspzip
126 | ///
127 | /// The arguments to use for the bspzip process
128 | protected abstract string GetProcessArguments();
129 |
130 | ///
131 | /// Save the current settings in settings.xml
132 | /// Log any error that may happen while saving
133 | ///
134 | protected void SaveSettings()
135 | {
136 | try
137 | {
138 | XmlUtils.SerializeSettings(toolSettings);
139 | }
140 | catch (SettingsSerializationException ex)
141 | {
142 | logsOutput.AppendLine(ex.GetMessageAndInner());
143 | logsOutput.AppendLine();
144 | }
145 | }
146 |
147 | ///
148 | /// Update the values of based on last parameters used
149 | /// And save them in settings.xml
150 | ///
151 | protected abstract void UpdateSettings();
152 |
153 | ///
154 | /// Delegate function used to log the process outputs
155 | ///
156 | ///
157 | ///
158 | private void ProcessOutputHandler(object sender, DataReceivedEventArgs e)
159 | {
160 | logsOutput.AppendLine(e.Data);
161 | }
162 |
163 | ///
164 | /// Delegate function used to log the process errors
165 | ///
166 | ///
167 | ///
168 | private void ProcessErrorHandler(object sender, DataReceivedEventArgs e)
169 | {
170 | logsOutput.AppendLine(e.Data);
171 | }
172 |
173 | #endregion
174 |
175 | }
176 |
177 | }
178 |
--------------------------------------------------------------------------------
/BspZipGUI/Tool/Utils/FunctionalException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace BspZipGUI.Tool.Utils
8 | {
9 |
10 | ///
11 | /// Abstract Exception that other functional Exception will inherit
12 | ///
13 | internal abstract class FunctionalException : Exception
14 | {
15 | ///
16 | ///
17 | ///
18 | public FunctionalException() { }
19 |
20 | ///
21 | ///
22 | ///
23 | ///
24 | public FunctionalException(string message) : base(message) { }
25 |
26 | ///
27 | ///
28 | ///
29 | ///
30 | ///
31 | public FunctionalException(string message, Exception inner) : base(message, inner) { }
32 |
33 | ///
34 | /// Return the Message of Exception and the message of InnerException if available
35 | ///
36 | /// Exception message and the InnerException message if available
37 | public string GetMessageAndInner()
38 | {
39 | string errorMessage = Message;
40 | if (InnerException != null)
41 | {
42 | errorMessage += "\n" + InnerException.Message;
43 | }
44 | return errorMessage;
45 | }
46 | }
47 |
48 | ///
49 | /// Exception used when an unexpected error happen during the serialization / deserialization of the settings
50 | ///
51 | [Serializable]
52 | internal class SettingsSerializationException : FunctionalException
53 | {
54 | ///
55 | ///
56 | ///
57 | public SettingsSerializationException() { }
58 |
59 | ///
60 | ///
61 | ///
62 | ///
63 | public SettingsSerializationException(string message) : base(message) { }
64 |
65 | ///
66 | ///
67 | ///
68 | ///
69 | ///
70 | public SettingsSerializationException(string message, Exception inner) : base(message, inner) { }
71 |
72 | }
73 |
74 |
75 | ///
76 | /// Exception used when an unexpected error happen during the creation of the list of files to pack
77 | ///
78 | [Serializable]
79 | internal class FilePackCreationException : FunctionalException
80 | {
81 | ///
82 | ///
83 | ///
84 | public FilePackCreationException() { }
85 |
86 | ///
87 | ///
88 | ///
89 | ///
90 | public FilePackCreationException(string message) : base(message) { }
91 |
92 | ///
93 | ///
94 | ///
95 | ///
96 | ///
97 | public FilePackCreationException(string message, Exception inner) : base(message, inner) { }
98 |
99 | }
100 |
101 |
102 | ///
103 | /// Exception used when an unexpected error happen during the creation of the bsp backup
104 | ///
105 | [Serializable]
106 | internal class BspBackupCreationException : FunctionalException
107 | {
108 | ///
109 | ///
110 | ///
111 | public BspBackupCreationException() { }
112 |
113 | ///
114 | ///
115 | ///
116 | ///
117 | public BspBackupCreationException(string message) : base(message) { }
118 |
119 | ///
120 | ///
121 | ///
122 | ///
123 | ///
124 | public BspBackupCreationException(string message, Exception inner) : base(message, inner) { }
125 |
126 | }
127 |
128 | ///
129 | /// Exception used when an unexpected error happen during the bspzip execution
130 | ///
131 | [Serializable]
132 | internal class BspZipExecutionException : FunctionalException
133 | {
134 | ///
135 | ///
136 | ///
137 | public BspZipExecutionException() { }
138 |
139 | ///
140 | ///
141 | ///
142 | ///
143 | public BspZipExecutionException(string message) : base(message) { }
144 |
145 | ///
146 | ///
147 | ///
148 | ///
149 | ///
150 | public BspZipExecutionException(string message, Exception inner) : base(message, inner) { }
151 |
152 | }
153 |
154 | ///
155 | /// Exception used when the process encounters one or multiple paths that are longer than
156 | ///
157 | [Serializable]
158 | internal class MaxPathSizeLimitException : FunctionalException
159 | {
160 | ///
161 | ///
162 | ///
163 | public MaxPathSizeLimitException() { }
164 |
165 | ///
166 | ///
167 | ///
168 | ///
169 | public MaxPathSizeLimitException(string message) : base(message) { }
170 |
171 | ///
172 | ///
173 | ///
174 | ///
175 | ///
176 | public MaxPathSizeLimitException(string message, Exception inner) : base(message, inner) { }
177 |
178 | }
179 |
180 | }
181 |
--------------------------------------------------------------------------------
/BspZipGUI/App.xaml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | 30
15 | 2
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
41 |
42 |
45 |
46 |
49 |
50 |
53 |
54 |
55 |
56 |
57 |
61 |
62 |
66 |
67 |
72 |
73 |
79 |
80 |
81 |
88 |
89 |
92 |
93 |
98 |
103 |
104 |
109 |
110 |
114 |
115 |
121 |
122 |
125 |
126 |
129 |
130 |
131 |
132 |
136 |
137 |
138 |
139 |
--------------------------------------------------------------------------------
/BspZipGUI/Tool/Execute/Pack.cs:
--------------------------------------------------------------------------------
1 | using BspZipGUI.Models;
2 | using BspZipGUI.Tool.Utils;
3 | using BspZipGUI.Tool.Xml;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Diagnostics;
7 | using System.Linq;
8 | using System.Text;
9 | using System.Threading.Tasks;
10 |
11 | namespace BspZipGUI.Tool.Execute
12 | {
13 | internal class Pack : Bspzip
14 | {
15 |
16 | #region Attributes
17 |
18 | ///
19 | /// The custom directory with the files to pack
20 | ///
21 | private readonly MapConfig mapContent;
22 |
23 | ///
24 | /// The multiple custom directory with the files to pack
25 | ///
26 | private readonly MultiMapConfig multiMapContent;
27 |
28 | ///
29 | /// Only pack specific files types in each specific subfolders
30 | ///
31 | private readonly bool useWhitelist;
32 |
33 | ///
34 | /// Path of the BSP to create
35 | ///
36 | private readonly string outputBspPath;
37 |
38 | #endregion
39 |
40 | #region Constructor
41 |
42 | public Pack(ToolSettings toolSettings, GameConfig game, string bspPath, LogText logsOutput, MapConfig mapContent, string outputBspPath, bool useWhitelist) :
43 | base(toolSettings, game, bspPath, logsOutput)
44 | {
45 | this.mapContent = mapContent;
46 | this.outputBspPath = outputBspPath;
47 | this.useWhitelist = useWhitelist;
48 | }
49 |
50 | public Pack(ToolSettings toolSettings, GameConfig game, string bspPath, LogText logsOutput, MultiMapConfig multiMapContent, string outputBspPath, bool useWhitelist) :
51 | base(toolSettings, game, bspPath, logsOutput)
52 | {
53 | this.multiMapContent = multiMapContent;
54 | this.outputBspPath = outputBspPath;
55 | this.useWhitelist = useWhitelist;
56 | }
57 |
58 | #endregion
59 |
60 | #region Methods
61 |
62 | ///
63 | /// Start the packing for the current options
64 | ///
65 | /// Error when creating the list of file to pack
66 | /// Error when creating the bsp backup
67 | /// Error during bspzip execution
68 | public override void Start()
69 | {
70 | UpdateSettings();
71 | logsOutput.AppendLine();
72 | bool hasMaxPathSize;
73 | FilePack filePack = new FilePack(GetCustomDirectories(), useWhitelist, toolSettings.DirectoriesRestrictions);
74 | try
75 | {
76 | hasMaxPathSize = filePack.FindAllFilesToPack();
77 | filePack.OutputToFile();
78 | }
79 | catch (Exception ex)
80 | {
81 | throw new FilePackCreationException(MessageConstants.MessageListFilesFail, ex);
82 | }
83 | if (!System.IO.File.Exists(Constants.FilesListText))
84 | {
85 | // Just for safety, but the file is supposed to exist
86 | throw new FilePackCreationException(MessageConstants.MessageListFilesNotFound);
87 | }
88 | logsOutput.AppendLine("Created " + Constants.FilesListText);
89 | if (bspPath.Equals(outputBspPath))
90 | {
91 | // If we override the original BSP, we make a backup
92 | try
93 | {
94 | CreateBackupBsp();
95 | }
96 | catch (Exception ex)
97 | {
98 | throw new BspBackupCreationException(MessageConstants.MessageCopyBspFail, ex);
99 | }
100 | }
101 | try
102 | {
103 | StartProcess();
104 | }
105 | catch (Exception ex)
106 | {
107 | throw new BspZipExecutionException(MessageConstants.MessageBspzipFail, ex);
108 | }
109 | if (hasMaxPathSize)
110 | {
111 | // One or multiple path longer than MAX_PATH were encountered
112 | // bspzip.exe likely didn't pack correctly the files
113 | // We add the list to the logs and throw an exception
114 | logsOutput.AppendLine($"/!\\ {MessageConstants.MessageMaxPathSizeWarning} :");
115 | foreach (string path in filePack.MaxPathSizeList)
116 | {
117 | logsOutput.AppendLine($"- {path.Length} : \"{path}\"");
118 | }
119 | throw new MaxPathSizeLimitException(MessageConstants.MessageMaxPathSizeSuggestion);
120 | }
121 | }
122 |
123 | ///
124 | /// Return the arguments to launch bspzip.exe, to pack the files in a BSP
125 | ///
126 | ///
127 | protected override string GetProcessArguments()
128 | {
129 | // bspzip -addlist "" "" ""
130 | StringBuilder sb = new StringBuilder("-addlist ")
131 | .Append($"\"{bspPath}\" ")
132 | .Append($"\"{Constants.FilesListText}\" ")
133 | .Append($"\"{outputBspPath}\"");
134 | return sb.ToString();
135 | }
136 |
137 | ///
138 | ///
139 | ///
140 | protected override void UpdateSettings()
141 | {
142 | toolSettings.LastBsp = bspPath;
143 | toolSettings.LastGame = game.Name;
144 | if (mapContent != null)
145 | toolSettings.LastCustomDirectory = mapContent.Name;
146 | if (multiMapContent != null)
147 | toolSettings.LastMultiCustomDirectory = multiMapContent.Name;
148 | SaveSettings();
149 | }
150 |
151 | ///
152 | /// Get the list of custom directories to use for packing
153 | ///
154 | /// A list of directories paths cleaned from any extra character
155 | private ICollection GetCustomDirectories()
156 | {
157 | // Clean the directories path first
158 | CleanCustomDirectoriesPath();
159 | if (mapContent != null)
160 | return new List { mapContent.CleanedPath };
161 | if (multiMapContent != null)
162 | return multiMapContent.HashSetCleanedPath;
163 | return new List();
164 | }
165 |
166 | ///
167 | /// Remove any extra / from the custom directories
168 | ///
169 | private void CleanCustomDirectoriesPath()
170 | {
171 | if (mapContent != null)
172 | mapContent.CleanPath();
173 | if (multiMapContent != null)
174 | multiMapContent.CleanPaths();
175 | }
176 |
177 | #endregion
178 |
179 | }
180 |
181 | }
182 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.rsuser
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Mono auto generated files
17 | mono_crash.*
18 |
19 | # Build results
20 | [Dd]ebug/
21 | [Dd]ebugPublic/
22 | [Rr]elease/
23 | [Rr]eleases/
24 | x64/
25 | x86/
26 | [Aa][Rr][Mm]/
27 | [Aa][Rr][Mm]64/
28 | bld/
29 | [Bb]in/
30 | [Oo]bj/
31 | [Ll]og/
32 |
33 | # Visual Studio 2015/2017 cache/options directory
34 | .vs/
35 | # Uncomment if you have tasks that create the project's static files in wwwroot
36 | #wwwroot/
37 |
38 | # Visual Studio 2017 auto generated files
39 | Generated\ Files/
40 |
41 | # MSTest test Results
42 | [Tt]est[Rr]esult*/
43 | [Bb]uild[Ll]og.*
44 |
45 | # NUnit
46 | *.VisualState.xml
47 | TestResult.xml
48 | nunit-*.xml
49 |
50 | # Build Results of an ATL Project
51 | [Dd]ebugPS/
52 | [Rr]eleasePS/
53 | dlldata.c
54 |
55 | # Benchmark Results
56 | BenchmarkDotNet.Artifacts/
57 |
58 | # .NET Core
59 | project.lock.json
60 | project.fragment.lock.json
61 | artifacts/
62 |
63 | # StyleCop
64 | StyleCopReport.xml
65 |
66 | # Files built by Visual Studio
67 | *_i.c
68 | *_p.c
69 | *_h.h
70 | *.ilk
71 | *.meta
72 | *.obj
73 | *.iobj
74 | *.pch
75 | *.pdb
76 | *.ipdb
77 | *.pgc
78 | *.pgd
79 | *.rsp
80 | *.sbr
81 | *.tlb
82 | *.tli
83 | *.tlh
84 | *.tmp
85 | *.tmp_proj
86 | *_wpftmp.csproj
87 | *.log
88 | *.vspscc
89 | *.vssscc
90 | .builds
91 | *.pidb
92 | *.svclog
93 | *.scc
94 |
95 | # Chutzpah Test files
96 | _Chutzpah*
97 |
98 | # Visual C++ cache files
99 | ipch/
100 | *.aps
101 | *.ncb
102 | *.opendb
103 | *.opensdf
104 | *.sdf
105 | *.cachefile
106 | *.VC.db
107 | *.VC.VC.opendb
108 |
109 | # Visual Studio profiler
110 | *.psess
111 | *.vsp
112 | *.vspx
113 | *.sap
114 |
115 | # Visual Studio Trace Files
116 | *.e2e
117 |
118 | # TFS 2012 Local Workspace
119 | $tf/
120 |
121 | # Guidance Automation Toolkit
122 | *.gpState
123 |
124 | # ReSharper is a .NET coding add-in
125 | _ReSharper*/
126 | *.[Rr]e[Ss]harper
127 | *.DotSettings.user
128 |
129 | # JustCode is a .NET coding add-in
130 | .JustCode
131 |
132 | # TeamCity is a build add-in
133 | _TeamCity*
134 |
135 | # DotCover is a Code Coverage Tool
136 | *.dotCover
137 |
138 | # AxoCover is a Code Coverage Tool
139 | .axoCover/*
140 | !.axoCover/settings.json
141 |
142 | # Visual Studio code coverage results
143 | *.coverage
144 | *.coveragexml
145 |
146 | # NCrunch
147 | _NCrunch_*
148 | .*crunch*.local.xml
149 | nCrunchTemp_*
150 |
151 | # MightyMoose
152 | *.mm.*
153 | AutoTest.Net/
154 |
155 | # Web workbench (sass)
156 | .sass-cache/
157 |
158 | # Installshield output folder
159 | [Ee]xpress/
160 |
161 | # DocProject is a documentation generator add-in
162 | DocProject/buildhelp/
163 | DocProject/Help/*.HxT
164 | DocProject/Help/*.HxC
165 | DocProject/Help/*.hhc
166 | DocProject/Help/*.hhk
167 | DocProject/Help/*.hhp
168 | DocProject/Help/Html2
169 | DocProject/Help/html
170 |
171 | # Click-Once directory
172 | publish/
173 |
174 | # Publish Web Output
175 | *.[Pp]ublish.xml
176 | *.azurePubxml
177 | # Note: Comment the next line if you want to checkin your web deploy settings,
178 | # but database connection strings (with potential passwords) will be unencrypted
179 | *.pubxml
180 | *.publishproj
181 |
182 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
183 | # checkin your Azure Web App publish settings, but sensitive information contained
184 | # in these scripts will be unencrypted
185 | PublishScripts/
186 |
187 | # NuGet Packages
188 | *.nupkg
189 | # NuGet Symbol Packages
190 | *.snupkg
191 | # The packages folder can be ignored because of Package Restore
192 | **/[Pp]ackages/*
193 | # except build/, which is used as an MSBuild target.
194 | !**/[Pp]ackages/build/
195 | # Uncomment if necessary however generally it will be regenerated when needed
196 | #!**/[Pp]ackages/repositories.config
197 | # NuGet v3's project.json files produces more ignorable files
198 | *.nuget.props
199 | *.nuget.targets
200 |
201 | # Microsoft Azure Build Output
202 | csx/
203 | *.build.csdef
204 |
205 | # Microsoft Azure Emulator
206 | ecf/
207 | rcf/
208 |
209 | # Windows Store app package directories and files
210 | AppPackages/
211 | BundleArtifacts/
212 | Package.StoreAssociation.xml
213 | _pkginfo.txt
214 | *.appx
215 | *.appxbundle
216 | *.appxupload
217 |
218 | # Visual Studio cache files
219 | # files ending in .cache can be ignored
220 | *.[Cc]ache
221 | # but keep track of directories ending in .cache
222 | !?*.[Cc]ache/
223 |
224 | # Others
225 | ClientBin/
226 | ~$*
227 | *~
228 | *.dbmdl
229 | *.dbproj.schemaview
230 | *.jfm
231 | *.pfx
232 | *.publishsettings
233 | orleans.codegen.cs
234 |
235 | # Including strong name files can present a security risk
236 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
237 | #*.snk
238 |
239 | # Since there are multiple workflows, uncomment next line to ignore bower_components
240 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
241 | #bower_components/
242 |
243 | # RIA/Silverlight projects
244 | Generated_Code/
245 |
246 | # Backup & report files from converting an old project file
247 | # to a newer Visual Studio version. Backup files are not needed,
248 | # because we have git ;-)
249 | _UpgradeReport_Files/
250 | Backup*/
251 | UpgradeLog*.XML
252 | UpgradeLog*.htm
253 | ServiceFabricBackup/
254 | *.rptproj.bak
255 |
256 | # SQL Server files
257 | *.mdf
258 | *.ldf
259 | *.ndf
260 |
261 | # Business Intelligence projects
262 | *.rdl.data
263 | *.bim.layout
264 | *.bim_*.settings
265 | *.rptproj.rsuser
266 | *- [Bb]ackup.rdl
267 | *- [Bb]ackup ([0-9]).rdl
268 | *- [Bb]ackup ([0-9][0-9]).rdl
269 |
270 | # Microsoft Fakes
271 | FakesAssemblies/
272 |
273 | # GhostDoc plugin setting file
274 | *.GhostDoc.xml
275 |
276 | # Node.js Tools for Visual Studio
277 | .ntvs_analysis.dat
278 | node_modules/
279 |
280 | # Visual Studio 6 build log
281 | *.plg
282 |
283 | # Visual Studio 6 workspace options file
284 | *.opt
285 |
286 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
287 | *.vbw
288 |
289 | # Visual Studio LightSwitch build output
290 | **/*.HTMLClient/GeneratedArtifacts
291 | **/*.DesktopClient/GeneratedArtifacts
292 | **/*.DesktopClient/ModelManifest.xml
293 | **/*.Server/GeneratedArtifacts
294 | **/*.Server/ModelManifest.xml
295 | _Pvt_Extensions
296 |
297 | # Paket dependency manager
298 | .paket/paket.exe
299 | paket-files/
300 |
301 | # FAKE - F# Make
302 | .fake/
303 |
304 | # CodeRush personal settings
305 | .cr/personal
306 |
307 | # Python Tools for Visual Studio (PTVS)
308 | __pycache__/
309 | *.pyc
310 |
311 | # Cake - Uncomment if you are using it
312 | # tools/**
313 | # !tools/packages.config
314 |
315 | # Tabs Studio
316 | *.tss
317 |
318 | # Telerik's JustMock configuration file
319 | *.jmconfig
320 |
321 | # BizTalk build output
322 | *.btp.cs
323 | *.btm.cs
324 | *.odx.cs
325 | *.xsd.cs
326 |
327 | # OpenCover UI analysis results
328 | OpenCover/
329 |
330 | # Azure Stream Analytics local run output
331 | ASALocalRun/
332 |
333 | # MSBuild Binary and Structured Log
334 | *.binlog
335 |
336 | # NVidia Nsight GPU debugger configuration file
337 | *.nvuser
338 |
339 | # MFractors (Xamarin productivity tool) working folder
340 | .mfractor/
341 |
342 | # Local History for Visual Studio
343 | .localhistory/
344 |
345 | # BeatPulse healthcheck temp database
346 | healthchecksdb
347 |
348 | # Backup folder for Package Reference Convert tool in Visual Studio 2017
349 | MigrationBackup/
350 |
--------------------------------------------------------------------------------
/BspZipGUI/Tool/Execute/FilePack.cs:
--------------------------------------------------------------------------------
1 | using BspZipGUI.Tool.Utils;
2 | using BspZipGUI.Tool.Xml;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace BspZipGUI.Tool.Execute
10 | {
11 | internal class FilePack
12 | {
13 |
14 | #region Attributes
15 |
16 | ///
17 | /// The list of files to pack: <internalPath, externalPath>
18 | ///
19 | private readonly IDictionary filesPathsList;
20 |
21 | ///
22 | /// List of pairs of <customDirectoryPath, length>
23 | ///
24 | private readonly ICollection> customDirectoriesPairs;
25 |
26 | ///
27 | /// The list of base directory and extension allowed to be packed
28 | ///
29 | private readonly ICollection directoriesRestrictions;
30 |
31 | ///
32 | /// Use the list of directory whitelist when packing
33 | ///
34 | private readonly bool useWhitelist;
35 |
36 | ///
37 | /// Store the list of paths that are longer than
38 | ///
39 | public readonly HashSet MaxPathSizeList;
40 |
41 | #endregion
42 |
43 | #region Constructor
44 |
45 | public FilePack(ICollection customDirectories, bool useWhitelist, ICollection directoriesRestrictions)
46 | {
47 | this.customDirectoriesPairs = new List>();
48 | foreach (string customDirectory in customDirectories)
49 | {
50 | // Each directory path will be cleaned from any ending '/', so + 1 for the length
51 | this.customDirectoriesPairs.Add(new KeyValuePair(customDirectory, customDirectory.Length + 1));
52 | }
53 | this.filesPathsList = new Dictionary();
54 | this.directoriesRestrictions = directoriesRestrictions;
55 | this.useWhitelist = useWhitelist;
56 | this.MaxPathSizeList = new HashSet();
57 | }
58 |
59 | #endregion
60 |
61 | #region Methods - Find Files
62 |
63 | ///
64 | /// Find all the files to pack and store them in the list
65 | ///
66 | /// true if one or multiple paths are longer than , false otherwise
67 | public bool FindAllFilesToPack()
68 | {
69 | if (useWhitelist)
70 | {
71 | // Add only the files matching specific extensions (defined in the Settings)
72 | return AddAllFilesFromWhitelistDirectories();
73 | }
74 | else
75 | {
76 | // Add every single file from the directories and subdirectories, regardless of extension
77 | return AddAllFilesFromAnyDirectories();
78 | }
79 | }
80 |
81 | ///
82 | /// Add every single files from the directories, to , regardless of their extensions
83 | ///
84 | /// true if one or multiple paths are longer than , false otherwise
85 | private bool AddAllFilesFromAnyDirectories()
86 | {
87 | bool hasMaxPathSize = false;
88 | foreach (KeyValuePair customDirectoryPair in customDirectoriesPairs)
89 | {
90 | List filesList = FileUtils.GetFilesListRecursive(customDirectoryPair.Key);
91 | if (filesList != null)
92 | {
93 | foreach (string path in filesList)
94 | {
95 | AppendPath(path, customDirectoryPair.Value);
96 | // bspzip.exe will not behave correctly if a very long path is in the file
97 | if (path.Length >= Constants.MAX_PATH)
98 | {
99 | MaxPathSizeList.Add(path);
100 | hasMaxPathSize = true;
101 | }
102 | }
103 | }
104 | }
105 | return hasMaxPathSize;
106 | }
107 |
108 | ///
109 | /// Add files matching specific extensions, located in specific subdirectories, to
110 | ///
111 | /// true if one or multiple paths are longer than , false otherwise
112 | private bool AddAllFilesFromWhitelistDirectories()
113 | {
114 | bool hasMaxPathSize = false;
115 | if (directoriesRestrictions != null)
116 | {
117 | // Go through each whitelisted subdirectory (materials, models,...)
118 | foreach (DirectoryRestrictions directoryRestrictions in directoriesRestrictions)
119 | {
120 | HashSet allowedExtensions = new HashSet(directoryRestrictions.AllowedExtension);
121 |
122 | // Go through each custom directory
123 | foreach (KeyValuePair customDirectoryPair in customDirectoriesPairs)
124 | {
125 | // Combine the custom directory path + the whitelisted subdirectory
126 | string subDirectory = System.IO.Path.Combine(customDirectoryPair.Key, directoryRestrictions.DirectoryName);
127 | if (System.IO.Directory.Exists(subDirectory))
128 | {
129 | List filesList = FileUtils.GetFilesListRecursive(subDirectory);
130 | if (filesList != null)
131 | {
132 | foreach (string path in filesList)
133 | {
134 | // Verify the file extension
135 | if (FileUtils.IsExtension(path, allowedExtensions))
136 | {
137 | AppendPath(path, customDirectoryPair.Value);
138 | // bspzip.exe will not behave correctly if a very long path is in the file
139 | if (path.Length >= Constants.MAX_PATH)
140 | {
141 | MaxPathSizeList.Add(path);
142 | hasMaxPathSize = true;
143 | }
144 | }
145 | }
146 | }
147 | }
148 | }
149 | }
150 | }
151 | return hasMaxPathSize;
152 | }
153 |
154 | ///
155 | /// Append a given file path to
156 | ///
157 | /// Absolute path of a file
158 | private void AppendPath(string externalPath, int customDirectoryLength)
159 | {
160 | string internalPath = GetInternalPath(externalPath, customDirectoryLength);
161 | if (!filesPathsList.ContainsKey(internalPath))
162 | filesPathsList.Add(new KeyValuePair(internalPath, externalPath));
163 | }
164 |
165 | ///
166 | /// Get the local path of a given file (based on the custom directory)
167 | ///
168 | /// Absolute path of a file
169 | /// The relative path to save in the txt file used by bspzip.exe
170 | private string GetInternalPath(string externalPath, int customDirectoryLength)
171 | {
172 | // e.g. c:\programfiles\....\materials\myFolder\texture.vtf
173 | // => materials/myFolder/texture.vtf
174 | return externalPath.Substring(customDirectoryLength).
175 | Replace(Constants.Backslash, Constants.Slash);
176 | }
177 |
178 | #endregion
179 |
180 | #region Methods - Write List
181 |
182 | ///
183 | /// Create filesList.txt with the paths of each files, located in
184 | ///
185 | /// In case there is an error during the file creation
186 | public void OutputToFile()
187 | {
188 | List outputLines = new List();
189 | foreach (KeyValuePair entry in filesPathsList)
190 | {
191 | outputLines.Add(entry.Key);
192 | outputLines.Add(entry.Value);
193 | }
194 |
195 | if (System.IO.File.Exists(Constants.FilesListText))
196 | {
197 | System.IO.File.Delete(Constants.FilesListText);
198 | }
199 | System.IO.File.WriteAllLines(Constants.FilesListText, outputLines);
200 | }
201 |
202 | #endregion
203 |
204 | }
205 |
206 |
207 | }
208 |
--------------------------------------------------------------------------------
/BspZipGUI/Tool/Utils/FileUtils.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace BspZipGUI.Tool.Utils
8 | {
9 | ///
10 | /// Enum to handle File Browser Dialog and Save Browser Dialog
11 | ///
12 | internal enum FileFilters
13 | {
14 | None,
15 | Bsp,
16 | Zip,
17 | BspZipExe,
18 | GameinfoTxt
19 | }
20 |
21 | ///
22 | /// Class containing useful file related functions
23 | ///
24 | internal static class FileUtils
25 | {
26 | #region Constants
27 |
28 | private const string filterGameinfoTxt = "Gameinfo (gameinfo.txt)|gameinfo.txt|Text files (*.txt)|*.txt|All files (*.*)|*.*";
29 | private const string filterBsp = "BSP Files (*.bsp)| *.bsp";
30 | private const string filterZip = "ZIP Files (*.zip)| *.zip";
31 | private const string filterBspZipExe = "BspZip (bspzip.exe)| bspzip.exe|Executable files (*.exe)|*.exe";
32 |
33 | private const string titleBspInput = "Select a .bsp";
34 | private const string titleBspZipExe = "Select bspzip.exe file";
35 | private const string titleGameinfoTxt = "Select gameinfo.txt file";
36 | private const string titleBspOutput = "Save .bsp as";
37 | private const string titleZipOutput = "Save .zip as";
38 |
39 | private const string titleDirectory = "Select a directory";
40 | private const string directorySelection = "[Folder Selection]";
41 | private const string searchPatternAny = "*.*";
42 |
43 | #endregion
44 |
45 | #region Methods - Files / Folders
46 |
47 | ///
48 | /// Read contents of an embedded resource file
49 | ///
50 | /// An exception of any type, if there is an error when reading the stream
51 | public static string ReadResourceFile(string filename)
52 | {
53 | System.Reflection.Assembly thisAssembly = System.Reflection.Assembly.GetExecutingAssembly();
54 | using (System.IO.Stream stream = thisAssembly.GetManifestResourceStream(filename))
55 | {
56 | using (System.IO.StreamReader reader = new System.IO.StreamReader(stream))
57 | {
58 | return reader.ReadToEnd();
59 | }
60 | }
61 | }
62 |
63 | ///
64 | /// Tries to get the directory name of a given path
65 | /// Remove any extra '/' in the path and '/' becomes '\'
66 | ///
67 | /// The path of a file or directory
68 | /// The directory path if successful, null otherwise
69 | public static string TryGetDirectoryName(string path)
70 | {
71 | try
72 | {
73 | return System.IO.Path.GetDirectoryName(path);
74 | }
75 | catch
76 | {
77 | return null;
78 | }
79 | }
80 |
81 | ///
82 | /// Get the list of all files in a given directory and its subdirectories
83 | ///
84 | /// The path of the directory
85 | /// An exception of any type, if there is an error getting the list of files
86 | /// The path of all files in the directories, null if the directory doesn't exist
87 | public static List GetFilesListRecursive(string directory)
88 | {
89 | if (System.IO.Directory.Exists(directory))
90 | {
91 | string[] files = System.IO.Directory.GetFiles(directory, searchPatternAny, System.IO.SearchOption.AllDirectories);
92 | return new List(files);
93 | }
94 | return null;
95 | }
96 |
97 | ///
98 | /// Check if the name of a file is the same as an expected one
99 | ///
100 | /// The path of the file
101 | /// Expected file name
102 | /// true if it's the same file name, false otherwise
103 | public static bool IsFileName(string path, string expectedFile)
104 | {
105 | string file = System.IO.Path.GetFileName(path).ToLower();
106 | return file.Equals(expectedFile.ToLower());
107 | }
108 |
109 | ///
110 | /// Check if the extension of a given file is matching a specific extension
111 | ///
112 | /// Path of the file
113 | /// An extension
114 | /// True if the file has the good extension, false otherwise
115 | public static bool IsExtension(string fileName, string allowedExtension)
116 | {
117 | return allowedExtension.Equals(System.IO.Path.GetExtension(fileName));
118 | }
119 |
120 | ///
121 | /// Check if the extension of a given file is matching a list of extensions
122 | ///
123 | /// Path of the file
124 | /// List of extensions
125 | /// True if the file has the good extension, false otherwise
126 | public static bool IsExtension(string fileName, HashSet allowedExtensions)
127 | {
128 | return allowedExtensions.Contains(System.IO.Path.GetExtension(fileName));
129 | }
130 |
131 | ///
132 | /// Clean the path of a directory by removing extra '/' within the path
133 | ///
134 | /// Path of a directory
135 | /// The cleaned directory path
136 | public static string CleanDirectoryPath(string path)
137 | {
138 | return TryGetDirectoryName(path + Constants.Slash);
139 | }
140 |
141 | #endregion
142 |
143 | #region Methods - Dialog File / Folder
144 |
145 | ///
146 | /// Open the File Browser Dialog with the given preset ()
147 | ///
148 | /// Filter for the preset parameters
149 | /// The path of the selected file, null if none
150 | public static string OpenFileDialog(FileFilters filter)
151 | {
152 | switch (filter)
153 | {
154 | case FileFilters.Bsp:
155 | return OpenFileDialog(filterBsp, titleBspInput);
156 | case FileFilters.BspZipExe:
157 | return OpenFileDialog(filterBspZipExe, titleBspZipExe);
158 | case FileFilters.GameinfoTxt:
159 | return OpenFileDialog(filterGameinfoTxt, titleGameinfoTxt);
160 | case FileFilters.None:
161 | default:
162 | break;
163 | }
164 | return OpenFileDialog(string.Empty, string.Empty);
165 | }
166 |
167 | ///
168 | /// Open the File Browser Dialog with given parameters
169 | ///
170 | /// Type of files to filter in the File Dialog
171 | /// Title of the File Dialog
172 | ///
173 | private static string OpenFileDialog(string filter, string title)
174 | {
175 | Microsoft.Win32.FileDialog fileDialog = new Microsoft.Win32.OpenFileDialog
176 | {
177 | Filter = filter,
178 | Title = title
179 | };
180 | bool? result = fileDialog.ShowDialog();
181 | if (result == true)
182 | {
183 | return fileDialog.FileName;
184 | }
185 | return null;
186 | }
187 |
188 | ///
189 | /// Open the File Browser Dialog as a Folder Browser Dialog
190 | /// Way better than the default "System.Windows.Forms.FolderBrowserDialog"
191 | ///
192 | /// Returns the selected folder, null if none
193 | public static string OpenFolderDialog()
194 | {
195 | Microsoft.Win32.FileDialog folderDialog = new Microsoft.Win32.OpenFileDialog
196 | {
197 | CheckFileExists = false, // Allow for the selection of a directory
198 | Title = titleDirectory,
199 | FileName = directorySelection // Default name
200 | };
201 | bool? result = folderDialog.ShowDialog();
202 | if (result == true)
203 | {
204 | return System.IO.Path.GetDirectoryName(folderDialog.FileName);
205 | }
206 | return null;
207 | }
208 |
209 | ///
210 | /// Open the Save File Browser Dialog with the given preset () and parameters
211 | ///
212 | /// Filter for the preset parameters
213 | /// Default filename
214 | /// Default extension
215 | /// Intitial directory to open the File Dialog in
216 | /// The path of the file to save, null if none
217 | public static string SaveFileDialog(FileFilters filter, string defaultFileName, string defaultExt, string initialDirectory = "")
218 | {
219 | switch (filter)
220 | {
221 | case FileFilters.Bsp:
222 | return SaveFileDialog(filterBsp, titleBspOutput, defaultFileName, defaultExt, initialDirectory);
223 | case FileFilters.Zip:
224 | return SaveFileDialog(filterZip, titleZipOutput, defaultFileName, defaultExt, initialDirectory);
225 | case FileFilters.None:
226 | default:
227 | break;
228 | }
229 | return SaveFileDialog(string.Empty, string.Empty, defaultFileName, defaultExt, initialDirectory);
230 | }
231 |
232 | ///
233 | /// Open the Save File Browser Dialog with the given parameters
234 | ///
235 | /// Type of files to filter in the File Dialog
236 | /// Title of the File Dialog
237 | /// Default filename
238 | /// Default extension
239 | /// Intitial directory to open the File Dialog in
240 | /// The path of the file to save, null if none
241 | private static string SaveFileDialog(string filter, string title, string defaultFileName, string defaultExt, string initialDirectory)
242 | {
243 | Microsoft.Win32.FileDialog saveDialog = new Microsoft.Win32.SaveFileDialog
244 | {
245 | InitialDirectory = initialDirectory,
246 | Filter = filter,
247 | FileName = defaultFileName,
248 | DefaultExt = defaultExt,
249 | Title = title,
250 | };
251 |
252 | bool? result = saveDialog.ShowDialog();
253 | if (result == true)
254 | {
255 | return saveDialog.FileName;
256 | }
257 | return null;
258 | }
259 |
260 | #endregion
261 |
262 | }
263 | }
264 |
--------------------------------------------------------------------------------
/BspZipGUI/Tool/Xml/ToolSettings.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Collections.ObjectModel;
4 | using System.ComponentModel;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 | using System.Xml.Serialization;
9 |
10 | namespace BspZipGUI.Tool.Xml
11 | {
12 |
13 | #region Class - Settings
14 |
15 | ///
16 | /// Store all settings of the user
17 | ///
18 | [Serializable]
19 | [XmlRoot("AppSettings")]
20 | public class ToolSettings
21 | {
22 |
23 | #region Attributes
24 |
25 | ///
26 | /// Last BSP loaded in the tool
27 | ///
28 | [XmlElement(ElementName = "LastBsp", Order = 1)]
29 | public string LastBsp { get; set; }
30 |
31 | ///
32 | /// Last game name loaded by the tool
33 | ///
34 | [XmlElement(ElementName = "LastGame", Order = 2)]
35 | public string LastGame { get; set; }
36 |
37 | ///
38 | /// Last custom files directory name loaded by the tool
39 | ///
40 | [XmlElement(ElementName = "LastCustomDirectory", Order = 3)]
41 | public string LastCustomDirectory { get; set; }
42 |
43 | ///
44 | /// Last directory path loaded by the tool for extractions
45 | ///
46 | [XmlElement(ElementName = "LastExtractDirectory", Order = 4)]
47 | public string LastExtractDirectory { get; set; }
48 |
49 | ///
50 | /// Is the bspzip output written synchronously (1) or asynchronously (0)
51 | ///
52 | [XmlIgnore]
53 | public bool IsSyncLogs { get; private set; }
54 |
55 | ///
56 | /// Serialized value to represent
57 | ///
58 | [XmlElement(ElementName = "IsSyncLogs", Order = 5)]
59 | public string IsAsyncLogsSerialize
60 | {
61 | // This getter is automatically called when the xml file is serialized
62 | get { return IsSyncLogs ? "True" : "False"; }
63 | set
64 | {
65 | // This setter is automatically called when the xml file is deserialized
66 | if ("True".Equals(value))
67 | IsSyncLogs = true;
68 | else if ("False".Equals(value))
69 | IsSyncLogs = false;
70 | else
71 | IsSyncLogs = false; // Force Async if not defined in the config
72 | }
73 | }
74 |
75 | ///
76 | /// List of games configs (bspzip.exe directory)
77 | ///
78 | [XmlArray(ElementName = "BspZipDirectories", Order = 6)]
79 | [XmlArrayItem(ElementName = "Game")]
80 | //public List GamesConfigs { get; set; }
81 | public ObservableCollection GamesConfigs { get; set; }
82 |
83 | ///
84 | /// List of maps configs (custom file directory)
85 | ///
86 | [XmlArray(ElementName = "CustomFilesDirectories", Order = 7)]
87 | [XmlArrayItem(ElementName = "Map")]
88 | public ObservableCollection MapsConfigs { get; set; }
89 |
90 | ///
91 | /// List of base directories the tool can browse and the file extensions allowed
92 | ///
93 | [XmlArray(ElementName = "WhiteListDirectories", Order = 8)]
94 | [XmlArrayItem(ElementName = "Directory")]
95 | public ObservableCollection DirectoriesRestrictions { get; set; }
96 |
97 | ///
98 | /// List of multi maps configs (multiple custom file directories)
99 | ///
100 | [XmlArray(ElementName = "MultiCustomFilesDirectories", Order = 9)]
101 | [XmlArrayItem(ElementName = "Map")]
102 | public ObservableCollection MultiMapsConfigs { get; set; }
103 |
104 | ///
105 | /// Last multi custom files directory name loaded by the tool
106 | ///
107 | [XmlElement(ElementName = "LastMultiCustomDirectory", Order = 10)]
108 | public string LastMultiCustomDirectory { get; set; }
109 |
110 | #endregion
111 |
112 | #region Constructor
113 |
114 | public ToolSettings()
115 | {
116 | }
117 |
118 | #endregion
119 |
120 | #region Methods - Init Attributes
121 |
122 | ///
123 | /// Initialize the attributes that werent automatically initialized wtih the xml file (cause of missing parameters).
124 | /// And delete any invalid attribute
125 | ///
126 | public void InitAllAttributes()
127 | {
128 | if (GamesConfigs == null)
129 | {
130 | InitGamesConfigs();
131 | }
132 | else
133 | {
134 | // Delete any invalid game config (missing data that was removed from the xml)
135 | for (int i = GamesConfigs.Count - 1; i >= 0; i--)
136 | {
137 | if (!GamesConfigs[i].IsValid())
138 | {
139 | GamesConfigs.RemoveAt(i);
140 | }
141 | }
142 | }
143 | if (MapsConfigs == null)
144 | {
145 | InitMapsConfigs();
146 | }
147 | else
148 | {
149 | // Delete any invalid map config (missing data that was removed from the xml)
150 | for (int i = MapsConfigs.Count - 1; i >= 0; i--)
151 | {
152 | if (!MapsConfigs[i].IsValid())
153 | {
154 | MapsConfigs.RemoveAt(i);
155 | }
156 | }
157 | }
158 | if (MultiMapsConfigs == null)
159 | {
160 | InitMultiMapsConfigs();
161 | }
162 | else
163 | {
164 | // Delete any invalid map config (missing data that was removed from the xml)
165 | for (int i = MultiMapsConfigs.Count - 1; i >= 0; i--)
166 | {
167 | if (!MultiMapsConfigs[i].IsValid())
168 | {
169 | MultiMapsConfigs.RemoveAt(i);
170 | }
171 | else
172 | {
173 | // Delete any invalid directory in the list
174 | for (int j = MultiMapsConfigs[i].ListPath.Count - 1; j >= 0; j--)
175 | {
176 | if (MultiMapsConfigs[i].ListPath[j] == null)
177 | {
178 | MultiMapsConfigs[i].ListPath.RemoveAt(j);
179 | }
180 | }
181 | }
182 | }
183 | }
184 |
185 | if (DirectoriesRestrictions == null)
186 | {
187 | InitDirectoriesRestrictions();
188 | }
189 | else
190 | {
191 | // Delete any invalid directory restriction (missing data that was removed from the xml)
192 | for (int i = DirectoriesRestrictions.Count - 1; i >= 0; i--)
193 | {
194 | if (!DirectoriesRestrictions[i].IsValid())
195 | {
196 | DirectoriesRestrictions.RemoveAt(i);
197 | }
198 | }
199 | }
200 |
201 | if (LastBsp == null)
202 | {
203 | LastBsp = string.Empty;
204 | }
205 | if (LastCustomDirectory == null)
206 | {
207 | LastCustomDirectory = string.Empty;
208 | }
209 | if (LastMultiCustomDirectory == null)
210 | {
211 | LastMultiCustomDirectory = string.Empty;
212 | }
213 | if (LastGame == null)
214 | {
215 | LastGame = string.Empty;
216 | }
217 | if (LastExtractDirectory == null)
218 | {
219 | LastExtractDirectory = string.Empty;
220 | }
221 | }
222 |
223 | private void InitGamesConfigs()
224 | {
225 | GamesConfigs = new ObservableCollection();
226 | }
227 | private void InitMapsConfigs()
228 | {
229 | MapsConfigs = new ObservableCollection();
230 | }
231 | private void InitMultiMapsConfigs()
232 | {
233 | MultiMapsConfigs = new ObservableCollection();
234 | }
235 | private void InitDirectoriesRestrictions()
236 | {
237 | DirectoriesRestrictions = new ObservableCollection();
238 | }
239 |
240 | #endregion
241 |
242 | #region Methods - Find Configs
243 |
244 | ///
245 | /// Find the first MapConfig (custom files location) corresponding to the given name
246 | ///
247 | /// name to search
248 | /// Return the corresponding MapConfig. null if none found
249 | public MapConfig FindMapConfig(string name)
250 | {
251 | foreach (MapConfig mapConfig in MapsConfigs)
252 | {
253 | if (name.Equals(mapConfig.Name))
254 | {
255 | return mapConfig;
256 | }
257 | }
258 | return null;
259 | }
260 |
261 | ///
262 | /// Find the first MultiMapConfig (custom files location) corresponding to the given name
263 | ///
264 | /// name to search
265 | /// Return the corresponding MultiMapConfig. null if none found
266 | public MultiMapConfig FindMultiMapConfig(string name)
267 | {
268 | foreach (MultiMapConfig multiMapConfig in MultiMapsConfigs)
269 | {
270 | if (name.Equals(multiMapConfig.Name))
271 | {
272 | return multiMapConfig;
273 | }
274 | }
275 | return null;
276 | }
277 |
278 | ///
279 | /// Find the first GameConfig (bspzip.exe location) corresponding to the given name
280 | ///
281 | /// name to search
282 | /// Return the corresponding GameConfig. null if none found
283 | public GameConfig FindGameConfig(string name)
284 | {
285 | foreach (GameConfig gameConfig in GamesConfigs)
286 | {
287 | if (name.Equals(gameConfig.Name))
288 | {
289 | return gameConfig;
290 | }
291 | }
292 | return null;
293 | }
294 |
295 | #endregion
296 |
297 | }
298 |
299 | #endregion
300 |
301 | #region Class - GameConfig
302 |
303 | ///
304 | /// Store a game name and the path to its bspzip.exe
305 | ///
306 | [Serializable]
307 | public class GameConfig : INotifyPropertyChanged
308 | {
309 |
310 | #region Attributes
311 |
312 | private string name;
313 | private string bspZip;
314 | private string gameInfo;
315 |
316 | ///
317 | /// Name of the game
318 | ///
319 | public string Name
320 | {
321 | get => name;
322 | set
323 | {
324 | if (name != value)
325 | {
326 | name = value;
327 | NotifyPropertyChanged("Name");
328 | }
329 | }
330 | }
331 |
332 | ///
333 | /// Path to bspzip.exe
334 | ///
335 | public string BspZip
336 | {
337 | get => bspZip;
338 | set
339 | {
340 | if (bspZip != value)
341 | {
342 | bspZip = value;
343 | NotifyPropertyChanged("BspZip");
344 | }
345 | }
346 | }
347 |
348 | ///
349 | /// Path to the gameinfo.txt
350 | ///
351 | public string GameInfo
352 | {
353 | get => gameInfo;
354 | set
355 | {
356 | if (gameInfo != value)
357 | {
358 | gameInfo = value;
359 | NotifyPropertyChanged("GameInfo");
360 | }
361 | }
362 | }
363 |
364 | #endregion
365 |
366 | #region Constructor
367 |
368 | public GameConfig()
369 | {
370 | }
371 |
372 | ///
373 | /// Create a default GameConfig
374 | ///
375 | /// A new instance of
376 | public static GameConfig GetDefaultGameConfig()
377 | {
378 | return new GameConfig
379 | {
380 | Name = "New Game",
381 | BspZip = @"C:\Program Files (x86)\Steam\steamapps\common\Counter-Strike Global Offensive\bin\bspzip.exe",
382 | GameInfo = @"C:\Program Files (x86)\Steam\steamapps\common\Counter-Strike Global Offensive\csgo\gameinfo.txt"
383 | };
384 | }
385 |
386 | #endregion
387 |
388 | #region Methods
389 |
390 | ///
391 | /// Path to the folder of gameinfo.txt
392 | ///
393 | public string GameInfoFolder => System.IO.Path.GetDirectoryName(GameInfo);
394 |
395 | ///
396 | /// Verify if all values of the GameConfig are not null
397 | ///
398 | /// true if all value are not null, false otherwise
399 | public bool IsValid()
400 | {
401 | if (Name != null && BspZip != null && GameInfo != null)
402 | {
403 | return true;
404 | }
405 | return false;
406 | }
407 |
408 | ///
409 | /// Verify if the bspzip.exe and gameinfo.txt files exist
410 | ///
411 | /// true if the files exist, false otherwise
412 | public bool FilesExist()
413 | {
414 | if (System.IO.File.Exists(BspZip) && System.IO.File.Exists(GameInfo))
415 | {
416 | return true;
417 | }
418 | return false;
419 | }
420 |
421 | #endregion
422 |
423 | #region INotifyPropertyChanged
424 |
425 | public event PropertyChangedEventHandler PropertyChanged;
426 |
427 | public void NotifyPropertyChanged(string propName)
428 | {
429 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
430 | }
431 |
432 | #endregion
433 |
434 | }
435 |
436 | #endregion
437 |
438 | #region Class - MapConfig
439 |
440 | ///
441 | /// Store a map name and the path to its custom folder
442 | ///
443 | [Serializable]
444 | public class MapConfig : INotifyPropertyChanged
445 | {
446 |
447 | #region Attributes
448 |
449 | private string name;
450 | private string path;
451 |
452 | ///
453 | /// Name of the map
454 | ///
455 | public string Name
456 | {
457 | get => name;
458 | set
459 | {
460 | if (name != value)
461 | {
462 | name = value;
463 | NotifyPropertyChanged("Name");
464 | }
465 | }
466 | }
467 |
468 | ///
469 | /// Path to the custom folder with files to pack
470 | ///
471 | public string Path
472 | {
473 | get => path;
474 | set
475 | {
476 | if (path != value)
477 | {
478 | path = value;
479 | NotifyPropertyChanged("Path");
480 | }
481 | }
482 | }
483 |
484 | ///
485 | /// Extra string that will contains the directory path cleaned from extra character
486 | ///
487 | [XmlIgnore]
488 | public string CleanedPath { get; private set; }
489 |
490 | #endregion
491 |
492 | #region Constructor
493 |
494 | public MapConfig()
495 | {
496 | CleanedPath = null;
497 | }
498 |
499 | ///
500 | /// Create a default MapConfig
501 | ///
502 | /// A new instance of
503 | public static MapConfig GetDefaultMapConfig()
504 | {
505 | return new MapConfig
506 | {
507 | Name = "New Custom Folder",
508 | Path = @"C:\MyMappingProject\CurrentProject"
509 | };
510 | }
511 |
512 | #endregion
513 |
514 | #region Methods
515 |
516 | ///
517 | /// Clean the path of the directory by removing extra '/' within the path
518 | /// and storing it in
519 | ///
520 | public void CleanPath()
521 | {
522 | CleanedPath = Utils.FileUtils.CleanDirectoryPath(Path);
523 | }
524 |
525 | ///
526 | /// Verify if all values of the MapConfig are not null
527 | ///
528 | /// true if all value are not null, false otherwise
529 | public bool IsValid()
530 | {
531 | if (Name != null && Path != null)
532 | {
533 | return true;
534 | }
535 | return false;
536 | }
537 |
538 | ///
539 | /// Return true if the custom directory exist
540 | ///
541 | ///
542 | public bool DirectoryExists()
543 | {
544 | if (System.IO.Directory.Exists(Path))
545 | {
546 | return true;
547 | }
548 | return false;
549 | }
550 |
551 | #endregion
552 |
553 | #region INotifyPropertyChanged
554 |
555 | public event PropertyChangedEventHandler PropertyChanged;
556 |
557 | public void NotifyPropertyChanged(string propName)
558 | {
559 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
560 | }
561 |
562 | #endregion
563 |
564 | }
565 |
566 | #endregion
567 |
568 | #region Class - MultiMapConfig
569 |
570 | ///
571 | /// Store a map name and the paths to its custom folders
572 | ///
573 | [Serializable]
574 | public class MultiMapConfig : INotifyPropertyChanged
575 | {
576 |
577 | #region Attributes
578 |
579 | private string name;
580 |
581 | ///
582 | /// Name of the map
583 | ///
584 | [XmlElement(Order = 1)]
585 | public string Name
586 | {
587 | get => name;
588 | set
589 | {
590 | if (name != value)
591 | {
592 | name = value;
593 | NotifyPropertyChanged("Name");
594 | }
595 | }
596 | }
597 |
598 | ///
599 | /// List of paths to the custom folders with files to pack
600 | ///
601 | [XmlArray(ElementName = "Paths", Order = 2)]
602 | [XmlArrayItem(ElementName = "Path")]
603 | public ObservableCollection ListPath { get; set; }
604 |
605 | ///
606 | /// List of custom folders paths separated by a new line.
607 | /// Used by the Textbox
608 | ///
609 | [XmlIgnore]
610 | public string Path
611 | {
612 | get
613 | {
614 | const string separator = "\n";
615 | return string.Join(separator, ListPath);
616 | }
617 | }
618 |
619 | ///
620 | /// List of custom folders paths as a dashed list.
621 | /// Used for logs
622 | ///
623 | [XmlIgnore]
624 | public string PathAsDashedList
625 | {
626 | get
627 | {
628 | // Non breaking space = \u00A0
629 | const string separator = "\n-\u00A0";
630 | return (ListPath.Count > 0 ? "-\u00A0" : "") + string.Join(separator, ListPath);
631 | }
632 | }
633 |
634 | ///
635 | /// List that will contains all the directories paths cleaned from any extra character.
636 | /// Needed because modifying asynchronously a ObservableCollection is not allowed
637 | ///
638 | [XmlIgnore]
639 | public HashSet HashSetCleanedPath { get; private set; }
640 |
641 | #endregion
642 |
643 | #region Constructor
644 |
645 | public MultiMapConfig()
646 | {
647 | HashSetCleanedPath = new HashSet();
648 | }
649 |
650 | ///
651 | /// Create a default MultiMapConfig
652 | ///
653 | /// A new instance of
654 | public static MultiMapConfig GetDefaultMultiMapConfig()
655 | {
656 | return new MultiMapConfig
657 | {
658 | Name = "New Custom Folders",
659 | ListPath = new ObservableCollection()
660 | };
661 | }
662 |
663 | #endregion
664 |
665 | #region Methods
666 |
667 | ///
668 | /// Verify if all values of the MultiMapConfig are not null
669 | ///
670 | /// true if all value are not null, false otherwise
671 | public bool IsValid()
672 | {
673 | if (Name != null && ListPath != null)
674 | {
675 | return true;
676 | }
677 | return false;
678 | }
679 |
680 | ///
681 | /// Returns true if the list of path is not empty, false otherwise
682 | ///
683 | ///
684 | public bool IsNotEmpty()
685 | {
686 | return ListPath.Count > 0;
687 | }
688 |
689 | ///
690 | /// Verify if all custom directories exist
691 | ///
692 | /// True if all custom directories exist, False otherwise
693 | public bool DirectoriesExists()
694 | {
695 | foreach (string directory in ListPath)
696 | {
697 | if (!System.IO.Directory.Exists(directory))
698 | {
699 | return false;
700 | }
701 | }
702 | return true;
703 | }
704 |
705 | ///
706 | /// Get a list of all the non existing directories, in the Multi Custom folder config
707 | ///
708 | /// List of directories
709 | public List GetNonExistingDirectories()
710 | {
711 | List listDirectories = new List();
712 | foreach (string directory in ListPath)
713 | {
714 | if (!System.IO.Directory.Exists(directory))
715 | {
716 | listDirectories.Add(directory);
717 | }
718 | }
719 | return listDirectories;
720 | }
721 |
722 | ///
723 | /// Create a HashSet with all unique directories paths from
724 | ///
725 | /// A HashSet of string
726 | public HashSet GetHashSetFromList()
727 | {
728 | return new HashSet(ListPath);
729 | }
730 |
731 | ///
732 | /// Clear and insert every element from the HashSet parameter
733 | ///
734 | /// List of unique directory path
735 | public void SetHashSetToList(HashSet directoriesHashSet)
736 | {
737 | ListPath.Clear();
738 | foreach(string directory in directoriesHashSet)
739 | {
740 | ListPath.Add(directory);
741 | }
742 | }
743 |
744 | ///
745 | /// Clean the paths of the directories by removing extra '/' within the list of paths
746 | /// and storing them in
747 | ///
748 | public void CleanPaths()
749 | {
750 | HashSetCleanedPath.Clear();
751 | foreach (string path in ListPath)
752 | {
753 | HashSetCleanedPath.Add(Utils.FileUtils.CleanDirectoryPath(path));
754 | }
755 | }
756 |
757 | ///
758 | /// Force an GUI update on the list of directory, in the MainWindow
759 | ///
760 | public void NotifyDirectoryListUpdate()
761 | {
762 | // To update the ListBox
763 | NotifyPropertyChanged("ListPath");
764 | // To update the TextBox
765 | NotifyPropertyChanged("Path");
766 | }
767 |
768 | #endregion
769 |
770 | #region INotifyPropertyChanged
771 |
772 | public event PropertyChangedEventHandler PropertyChanged;
773 |
774 | public void NotifyPropertyChanged(string propName)
775 | {
776 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
777 | }
778 |
779 | #endregion
780 |
781 | }
782 |
783 | #endregion
784 |
785 | #region Class - DirectoryRestrictions
786 |
787 | ///
788 | /// Store a directory name and the list of allowed files
789 | ///
790 | [Serializable]
791 | public class DirectoryRestrictions : INotifyPropertyChanged
792 | {
793 |
794 | #region Attributes
795 |
796 | private string directoryName;
797 |
798 | ///
799 | /// Name of the directory (materials, models, ...)
800 | ///
801 | [XmlElement(Order = 1)]
802 | public string DirectoryName
803 | {
804 | get => directoryName;
805 | set
806 | {
807 | if (directoryName != value)
808 | {
809 | directoryName = value;
810 | NotifyPropertyChanged("DirectoryName");
811 | }
812 | }
813 | }
814 |
815 | ///
816 | /// Files Extensions allowed
817 | ///
818 | [XmlArray(ElementName = "Extensions", Order = 2)]
819 | [XmlArrayItem(ElementName = "Extension")]
820 | public List AllowedExtension { get; set; }
821 |
822 | ///
823 | /// String version of the extensions allowed separated by |
824 | ///
825 | [XmlIgnore]
826 | public string ExtensionStr
827 | {
828 | get
829 | {
830 | const string separator = "|";
831 | return string.Join(separator, AllowedExtension);
832 | }
833 | set
834 | {
835 | const char separator = '|';
836 | AllowedExtension = new List(value.Split(separator));
837 | }
838 | }
839 |
840 | #endregion
841 |
842 | #region Constructor
843 |
844 | public DirectoryRestrictions()
845 | {
846 | }
847 |
848 | ///
849 | /// Create a default DirectoryRestrictions
850 | ///
851 | /// A new instance of
852 | public static DirectoryRestrictions GetDefaultDirectoryRestrictions()
853 | {
854 | return new DirectoryRestrictions
855 | {
856 | DirectoryName = "directory_name",
857 | AllowedExtension = new List() { ".txt", ".jpg" }
858 | };
859 | }
860 |
861 | #endregion
862 |
863 | #region Methods
864 |
865 | ///
866 | /// Verify if all values of the DirectoryRestrictions are not null
867 | ///
868 | /// true if all value are not null, false otherwise
869 | public bool IsValid()
870 | {
871 | if (DirectoryName != null && AllowedExtension != null)
872 | {
873 | return true;
874 | }
875 | return false;
876 | }
877 |
878 | #endregion
879 |
880 | #region INotifyPropertyChanged
881 |
882 | public event PropertyChangedEventHandler PropertyChanged;
883 |
884 | public void NotifyPropertyChanged(string propName)
885 | {
886 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
887 | }
888 |
889 | #endregion
890 |
891 | }
892 |
893 | #endregion
894 |
895 | }
896 |
--------------------------------------------------------------------------------
/BspZipGUI/MainWindow.xaml:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | Bsp Packer
19 | Bsp Packer - Multiple
20 | Bsp Repack
21 | Bsp Extract
22 | Bsp Cubemaps
23 | Logs
24 | Settings
25 |
26 |
27 |
28 |
29 |
30 | Browse
31 | Game
32 | Custom Folder
33 | Custom Folders
34 | Bsp File
35 |
36 |
37 |
38 |
39 |
40 | Pack a custom folder into a BSP
41 |
42 | Pack Bsp
43 |
44 |
45 | Pack a custom folder into a BSP
46 |
47 |
48 | Use Directory Whitelist
49 | Only pack defined folders and files (Settings)
50 |
51 | Output to a new Bsp
52 | Pack the files into a new Bsp
53 |
54 |
55 |
56 | Pack multiple custom folders into a BSP
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 | Repack the BSP to compress it (or decompress it)
67 | Compressing may take several seconds depending of the size of the BSP
68 | /!\ Warning: Not available for every game (e.g. CS:GO)
69 |
70 |
71 | Compress Bsp
72 | Decompress Bsp
73 |
74 |
75 |
76 |
77 |
78 |
79 | Extract the content of the BSP into a directory or into a .zip file
80 | /!\ Warning: Using it on a repacked BSP will not work
81 |
82 |
83 | Extract to Directory
84 | Extract to zip
85 |
86 |
87 |
88 |
89 |
90 |
91 | Extract cubemaps of the BSP into a directory or delete all cubemaps
92 | /!\ Warning: Deleting cubemaps will actually delete every VTF packed in the map
93 |
94 |
95 | Extract cubemaps
96 | Delete cubemaps
97 |
98 |
99 |
100 |
101 |
102 |
103 | Directories Whitelist
104 | Custom Folders
105 | Custom Folders - Multiple
106 |
107 | Games
108 |
109 | Name
110 | Add...
111 | Add Directory
112 | Remove Selected
113 | Delete
114 | Setup Games
115 | Setup Custom Folders
116 | Setup Multiple Custom Folders
117 | Save Settings
118 |
119 | Bspzip Path
120 | Gameinfo Path
121 |
122 | Directory Path
123 | Directories
124 | Directory Name
125 | Allowed Extensions
126 | Separate extensions by '|'. For example: .vmt|.vtf
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
184 |
185 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
201 |
203 |
204 |
205 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
219 |
220 |
223 |
224 |
225 |
226 |
228 |
229 |
230 |
231 |
233 |
234 |
235 |
236 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
267 |
268 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
284 |
286 |
287 |
288 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
302 |
303 |
306 |
307 |
308 |
309 |
311 |
312 |
313 |
314 |
316 |
317 |
318 |
319 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
347 |
348 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
362 |
363 |
366 |
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 |
375 |
378 |
381 |
382 |
383 |
384 |
385 |
386 |
387 |
388 |
389 |
390 |
391 |
392 |
393 |
394 |
395 |
396 |
397 |
398 |
399 |
400 |
401 |
402 |
403 |
404 |
406 |
407 |
410 |
411 |
412 |
413 |
414 |
415 |
416 |
417 |
418 |
419 |
421 |
422 |
425 |
426 |
427 |
428 |
429 |
430 |
431 |
432 |
433 |
434 |
436 |
437 |
440 |
441 |
442 |
443 |
444 |
445 |
446 |
447 |
448 |
449 |
450 |
453 |
456 |
457 |
458 |
459 |
460 |
461 |
462 |
463 |
464 |
465 |
466 |
467 |
468 |
469 |
470 |
471 |
472 |
473 |
474 |
475 |
476 |
477 |
478 |
479 |
481 |
482 |
485 |
486 |
487 |
488 |
489 |
490 |
491 |
492 |
493 |
494 |
496 |
497 |
500 |
501 |
502 |
503 |
504 |
505 |
506 |
507 |
508 |
509 |
511 |
512 |
515 |
516 |
517 |
518 |
519 |
520 |
521 |
522 |
523 |
524 |
525 |
528 |
531 |
532 |
533 |
534 |
535 |
536 |
537 |
538 |
539 |
540 |
541 |
542 |
543 |
544 |
545 |
546 |
547 |
548 |
549 |
552 |
553 |
554 |
555 |
556 |
557 |
558 |
559 |
560 |
561 |
562 |
563 |
564 |
565 |
566 |
567 |
568 |
569 |
570 |
571 |
572 |
573 |
574 |
575 |
576 |
577 |
578 |
579 |
580 |
581 |
582 |
584 |
585 |
588 |
589 |
590 |
591 |
592 |
593 |
594 |
595 |
596 |
597 |
598 |
599 |
600 |
601 |
602 |
603 |
604 |
605 |
606 |
607 |
608 |
610 |
613 |
614 |
615 |
616 |
617 |
618 |
619 |
620 |
621 |
623 |
626 |
627 |
628 |
629 |
630 |
631 |
632 |
633 |
636 |
637 |
638 |
639 |
640 |
641 |
642 |
643 |
644 |
645 |
646 |
647 |
648 |
649 |
650 |
651 |
652 |
654 |
655 |
658 |
659 |
660 |
661 |
662 |
663 |
664 |
665 |
666 |
667 |
668 |
669 |
670 |
671 |
672 |
673 |
674 |
675 |
676 |
677 |
678 |
680 |
683 |
684 |
685 |
686 |
687 |
688 |
689 |
690 |
691 |
694 |
695 |
696 |
697 |
698 |
699 |
700 |
701 |
702 |
703 |
704 |
705 |
706 |
707 |
708 |
709 |
711 |
712 |
715 |
716 |
717 |
718 |
719 |
720 |
721 |
722 |
723 |
724 |
725 |
726 |
727 |
728 |
729 |
730 |
731 |
732 |
733 |
734 |
735 |
736 |
737 |
740 |
741 |
742 |
743 |
744 |
747 |
748 |
751 |
752 |
753 |
754 |
755 |
756 |
757 |
758 |
759 |
760 |
761 |
762 |
765 |
766 |
767 |
768 |
769 |
770 |
771 |
772 |
773 |
774 |
775 |
776 |
777 |
778 |
779 |
780 |
783 |
784 |
787 |
788 |
789 |
790 |
791 |
792 |
793 |
794 |
795 |
796 |
797 |
798 |
799 |
800 |
801 |
802 |
803 |
804 |
805 |
806 |
807 |
809 |
810 |
811 |
812 |
813 |
814 |
815 |
816 |
817 |
818 |
821 |
822 |
823 |
824 |
825 |
826 |
827 |
828 |
829 |
830 |
833 |
834 |
835 |
836 |
837 |
838 |
839 |
840 |
841 |
842 |
843 |
--------------------------------------------------------------------------------