├── app.config ├── README.md ├── Properties ├── Settings.settings ├── Settings.Designer.cs ├── AssemblyInfo.cs ├── Resources.Designer.cs └── Resources.resx ├── WZDumper ├── Program.cs ├── SafeToolStripLabel.cs ├── About.cs ├── About.Designer.cs ├── About.resx ├── MainForm.resx ├── WzXml.cs ├── MainForm.Designer.cs └── MainForm.cs ├── LICENSE ├── WzDumper.sln ├── .gitattributes ├── .gitignore └── WzDumper.csproj /app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WZ Dumper 2 | A tool to extract WZ files 3 | 4 | Requires MapleLib as a dependency: https://github.com/Xterminatorz/MapleLib 5 | 6 | Forum post: http://forum.ragezone.com/f921/wz-dumper-665433/ -------------------------------------------------------------------------------- /Properties/Settings.settings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /WZDumper/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Forms; 3 | 4 | namespace WzDumper { 5 | internal static class Program { 6 | /// 7 | /// The main entry point for the application. 8 | /// 9 | [STAThread] 10 | static void Main() { 11 | Application.EnableVisualStyles(); 12 | Application.SetCompatibleTextRenderingDefault(false); 13 | Application.Run(new MainForm()); 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Johnny 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /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 WzDumper.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.5.0.0")] 16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Resources; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("WZ Dumper")] 9 | [assembly: AssemblyDescription("A WZ File Dumper by Xterminator")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Xterminator")] 12 | [assembly: AssemblyProduct("WZ Dumper")] 13 | [assembly: AssemblyCopyright("")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("5571721f-fe78-4d1c-89d1-6c557be3a134")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | 36 | [assembly: AssemblyVersion("1.9.6.0")] 37 | [assembly: AssemblyFileVersion("1.9.6.0")] 38 | [assembly: NeutralResourcesLanguageAttribute("en-US")] 39 | -------------------------------------------------------------------------------- /WzDumper.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28010.2003 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WzDumper", "WzDumper.csproj", "{E252897F-9BF1-4AA3-AFD9-E0DF259B453C}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MapleLib", "..\MapleLib\MapleLib.csproj", "{28AAB36D-942E-4476-A000-0E9DE380F390}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {E252897F-9BF1-4AA3-AFD9-E0DF259B453C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {E252897F-9BF1-4AA3-AFD9-E0DF259B453C}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {E252897F-9BF1-4AA3-AFD9-E0DF259B453C}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {E252897F-9BF1-4AA3-AFD9-E0DF259B453C}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {28AAB36D-942E-4476-A000-0E9DE380F390}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {28AAB36D-942E-4476-A000-0E9DE380F390}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {28AAB36D-942E-4476-A000-0E9DE380F390}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {28AAB36D-942E-4476-A000-0E9DE380F390}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {3146CB88-72F8-4572-96D5-CA2C58BDE4D1} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /WZDumper/SafeToolStripLabel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Forms; 3 | 4 | namespace WzDumper { 5 | /// 6 | /// Provides a Sate Text property for a ToolStripStatusLabel 7 | /// 8 | public class SafeToolStripLabel : ToolStripStatusLabel { 9 | public override string Text { 10 | get { 11 | if ((Parent != null) && // Make sure that the container is already built 12 | (Parent.InvokeRequired)) // Is Invoke required? 13 | { 14 | GetString getTextDel = () => Text; 15 | string text = String.Empty; 16 | try { 17 | // Invoke the SetText operation from the Parent of the ToolStripStatusLabel 18 | text = (string)Parent.Invoke(getTextDel, null); 19 | } catch { 20 | } 21 | 22 | return text; 23 | } 24 | return base.Text; 25 | } 26 | 27 | set { 28 | // Get from the container if Invoke is required 29 | if ((Parent != null) && // Make sure that the container is already built 30 | (Parent.InvokeRequired)) // Is Invoke required? 31 | { 32 | SetText setTextDel = delegate (string text) { 33 | Text = text; 34 | }; 35 | 36 | try { 37 | // Invoke the SetText operation from the Parent of the ToolStripStatusLabel 38 | Parent.Invoke(setTextDel, new object[] { value }); 39 | } catch { 40 | } 41 | } else 42 | base.Text = value; 43 | } 44 | } 45 | 46 | #region Nested type: GetString 47 | 48 | private delegate string GetString(); 49 | 50 | #endregion 51 | 52 | #region Nested type: SetText 53 | 54 | private delegate void SetText(string text); 55 | 56 | #endregion 57 | } 58 | } -------------------------------------------------------------------------------- /WZDumper/About.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Reflection; 4 | using System.Windows.Forms; 5 | 6 | namespace WzDumper { 7 | internal sealed partial class About : Form { 8 | public About() { 9 | InitializeComponent(); 10 | Text = "About WZ Dumper"; 11 | appVer.Text = String.Format(CultureInfo.CurrentCulture, "{0} Version {1}", AssemblyProduct, AssemblyVersion); 12 | } 13 | 14 | #region Assembly Attribute Accessors 15 | 16 | /* 17 | public string AssemblyTitle { 18 | get { 19 | object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyTitleAttribute), false); 20 | if (attributes.Length > 0) { 21 | AssemblyTitleAttribute titleAttribute = (AssemblyTitleAttribute) attributes[0]; 22 | if (titleAttribute.Title != "") { 23 | return titleAttribute.Title; 24 | } 25 | } 26 | return System.IO.Path.GetFileNameWithoutExtension(Assembly.GetExecutingAssembly().CodeBase); 27 | } 28 | } 29 | */ 30 | 31 | private static string AssemblyVersion { get { return Assembly.GetExecutingAssembly().GetName().Version.ToString(); } } 32 | 33 | /* 34 | public string AssemblyDescription { 35 | get { 36 | object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyDescriptionAttribute), false); 37 | if (attributes.Length == 0) { 38 | return ""; 39 | } 40 | return ((AssemblyDescriptionAttribute) attributes[0]).Description; 41 | } 42 | } 43 | */ 44 | 45 | private static string AssemblyProduct { 46 | get { 47 | object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyProductAttribute), false); 48 | return attributes.Length == 0 ? "" : ((AssemblyProductAttribute) attributes[0]).Product; 49 | } 50 | } 51 | 52 | /* 53 | public string AssemblyCopyright { 54 | get { 55 | object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyCopyrightAttribute), false); 56 | if (attributes.Length == 0) { 57 | return ""; 58 | } 59 | return ((AssemblyCopyrightAttribute) attributes[0]).Copyright; 60 | } 61 | } 62 | */ 63 | 64 | /* 65 | public string AssemblyCompany { 66 | get { 67 | object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyCompanyAttribute), false); 68 | if (attributes.Length == 0) { 69 | return ""; 70 | } 71 | return ((AssemblyCompanyAttribute) attributes[0]).Company; 72 | } 73 | } 74 | */ 75 | 76 | #endregion 77 | 78 | private void Button1Click(object sender, EventArgs e) { 79 | Close(); 80 | } 81 | } 82 | } -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /Properties/Resources.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 WzDumper.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("WzDumper.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /WZDumper/About.Designer.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Forms; 2 | 3 | namespace WzDumper { 4 | sealed partial class About { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | protected override void Dispose(bool disposing) { 14 | if (disposing && (components != null)) { 15 | components.Dispose(); 16 | } 17 | base.Dispose(disposing); 18 | } 19 | 20 | #region Windows Form Designer generated code 21 | 22 | /// 23 | /// Required method for Designer support - do not modify 24 | /// the contents of this method with the code editor. 25 | /// 26 | private void InitializeComponent() { 27 | this.label1 = new System.Windows.Forms.Label(); 28 | this.button1 = new System.Windows.Forms.Button(); 29 | this.appVer = new System.Windows.Forms.Label(); 30 | this.label4 = new System.Windows.Forms.Label(); 31 | this.label5 = new System.Windows.Forms.Label(); 32 | this.label2 = new System.Windows.Forms.Label(); 33 | this.SuspendLayout(); 34 | // 35 | // label1 36 | // 37 | this.label1.AutoSize = true; 38 | this.label1.Font = new System.Drawing.Font("Tahoma", 8.25F); 39 | this.label1.Location = new System.Drawing.Point(15, 65); 40 | this.label1.Name = "label1"; 41 | this.label1.Size = new System.Drawing.Size(94, 13); 42 | this.label1.TabIndex = 0; 43 | this.label1.Text = "Snow for MapleLib"; 44 | // 45 | // button1 46 | // 47 | this.button1.Location = new System.Drawing.Point(76, 105); 48 | this.button1.Name = "button1"; 49 | this.button1.Size = new System.Drawing.Size(75, 23); 50 | this.button1.TabIndex = 3; 51 | this.button1.Text = "OK"; 52 | this.button1.UseVisualStyleBackColor = true; 53 | this.button1.Click += new System.EventHandler(this.Button1Click); 54 | // 55 | // appVer 56 | // 57 | this.appVer.AutoSize = true; 58 | this.appVer.Location = new System.Drawing.Point(48, 10); 59 | this.appVer.Name = "appVer"; 60 | this.appVer.Size = new System.Drawing.Size(103, 13); 61 | this.appVer.TabIndex = 4; 62 | this.appVer.Text = "WZ Dumper Version"; 63 | this.appVer.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; 64 | // 65 | // label4 66 | // 67 | this.label4.AutoSize = true; 68 | this.label4.Location = new System.Drawing.Point(14, 49); 69 | this.label4.Name = "label4"; 70 | this.label4.Size = new System.Drawing.Size(96, 13); 71 | this.label4.TabIndex = 5; 72 | this.label4.Text = "Special Thanks to:"; 73 | // 74 | // label5 75 | // 76 | this.label5.AutoSize = true; 77 | this.label5.Location = new System.Drawing.Point(59, 25); 78 | this.label5.Name = "label5"; 79 | this.label5.Size = new System.Drawing.Size(114, 13); 80 | this.label5.TabIndex = 6; 81 | this.label5.Text = "Created by Xterminator"; 82 | // 83 | // label2 84 | // 85 | this.label2.AutoSize = true; 86 | this.label2.Location = new System.Drawing.Point(14, 80); 87 | this.label2.Name = "label2"; 88 | this.label2.Size = new System.Drawing.Size(195, 13); 89 | this.label2.TabIndex = 1; 90 | this.label2.Text = "Traitor for his original DumpXML method"; 91 | // 92 | // About 93 | // 94 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 95 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 96 | this.ClientSize = new System.Drawing.Size(228, 140); 97 | this.Controls.Add(this.label5); 98 | this.Controls.Add(this.label4); 99 | this.Controls.Add(this.appVer); 100 | this.Controls.Add(this.button1); 101 | this.Controls.Add(this.label2); 102 | this.Controls.Add(this.label1); 103 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; 104 | this.MaximizeBox = false; 105 | this.MinimizeBox = false; 106 | this.Name = "About"; 107 | this.Padding = new System.Windows.Forms.Padding(9); 108 | this.ShowIcon = false; 109 | this.ShowInTaskbar = false; 110 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; 111 | this.Text = "About WZ Dumper"; 112 | this.ResumeLayout(false); 113 | this.PerformLayout(); 114 | 115 | } 116 | #endregion 117 | 118 | private System.Windows.Forms.Label label1; 119 | private System.Windows.Forms.Button button1; 120 | private System.Windows.Forms.Label appVer; 121 | private Label label4; 122 | private Label label5; 123 | private Label label2; 124 | 125 | } 126 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | project.fragment.lock.json 46 | artifacts/ 47 | 48 | *_i.c 49 | *_p.c 50 | *_i.h 51 | *.ilk 52 | *.meta 53 | *.obj 54 | *.pch 55 | *.pdb 56 | *.pgc 57 | *.pgd 58 | *.rsp 59 | *.sbr 60 | *.tlb 61 | *.tli 62 | *.tlh 63 | *.tmp 64 | *.tmp_proj 65 | *.log 66 | *.vspscc 67 | *.vssscc 68 | .builds 69 | *.pidb 70 | *.svclog 71 | *.scc 72 | 73 | # Chutzpah Test files 74 | _Chutzpah* 75 | 76 | # Visual C++ cache files 77 | ipch/ 78 | *.aps 79 | *.ncb 80 | *.opendb 81 | *.opensdf 82 | *.sdf 83 | *.cachefile 84 | *.VC.db 85 | *.VC.VC.opendb 86 | 87 | # Visual Studio profiler 88 | *.psess 89 | *.vsp 90 | *.vspx 91 | *.sap 92 | 93 | # TFS 2012 Local Workspace 94 | $tf/ 95 | 96 | # Guidance Automation Toolkit 97 | *.gpState 98 | 99 | # ReSharper is a .NET coding add-in 100 | _ReSharper*/ 101 | *.[Rr]e[Ss]harper 102 | *.DotSettings.user 103 | 104 | # JustCode is a .NET coding add-in 105 | .JustCode 106 | 107 | # TeamCity is a build add-in 108 | _TeamCity* 109 | 110 | # DotCover is a Code Coverage Tool 111 | *.dotCover 112 | 113 | # NCrunch 114 | _NCrunch_* 115 | .*crunch*.local.xml 116 | nCrunchTemp_* 117 | 118 | # MightyMoose 119 | *.mm.* 120 | AutoTest.Net/ 121 | 122 | # Web workbench (sass) 123 | .sass-cache/ 124 | 125 | # Installshield output folder 126 | [Ee]xpress/ 127 | 128 | # DocProject is a documentation generator add-in 129 | DocProject/buildhelp/ 130 | DocProject/Help/*.HxT 131 | DocProject/Help/*.HxC 132 | DocProject/Help/*.hhc 133 | DocProject/Help/*.hhk 134 | DocProject/Help/*.hhp 135 | DocProject/Help/Html2 136 | DocProject/Help/html 137 | 138 | # Click-Once directory 139 | publish/ 140 | 141 | # Publish Web Output 142 | *.[Pp]ublish.xml 143 | *.azurePubxml 144 | # TODO: Comment the next line if you want to checkin your web deploy settings 145 | # but database connection strings (with potential passwords) will be unencrypted 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 150 | # checkin your Azure Web App publish settings, but sensitive information contained 151 | # in these scripts will be unencrypted 152 | PublishScripts/ 153 | 154 | # NuGet Packages 155 | *.nupkg 156 | # The packages folder can be ignored because of Package Restore 157 | **/packages/* 158 | # except build/, which is used as an MSBuild target. 159 | !**/packages/build/ 160 | # Uncomment if necessary however generally it will be regenerated when needed 161 | #!**/packages/repositories.config 162 | # NuGet v3's project.json files produces more ignoreable files 163 | *.nuget.props 164 | *.nuget.targets 165 | 166 | # Microsoft Azure Build Output 167 | csx/ 168 | *.build.csdef 169 | 170 | # Microsoft Azure Emulator 171 | ecf/ 172 | rcf/ 173 | 174 | # Windows Store app package directories and files 175 | AppPackages/ 176 | BundleArtifacts/ 177 | Package.StoreAssociation.xml 178 | _pkginfo.txt 179 | 180 | # Visual Studio cache files 181 | # files ending in .cache can be ignored 182 | *.[Cc]ache 183 | # but keep track of directories ending in .cache 184 | !*.[Cc]ache/ 185 | 186 | # Others 187 | ClientBin/ 188 | ~$* 189 | *~ 190 | *.dbmdl 191 | *.dbproj.schemaview 192 | *.jfm 193 | *.pfx 194 | *.publishsettings 195 | node_modules/ 196 | orleans.codegen.cs 197 | 198 | # Since there are multiple workflows, uncomment next line to ignore bower_components 199 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 200 | #bower_components/ 201 | 202 | # RIA/Silverlight projects 203 | Generated_Code/ 204 | 205 | # Backup & report files from converting an old project file 206 | # to a newer Visual Studio version. Backup files are not needed, 207 | # because we have git ;-) 208 | _UpgradeReport_Files/ 209 | Backup*/ 210 | UpgradeLog*.XML 211 | UpgradeLog*.htm 212 | 213 | # SQL Server files 214 | *.mdf 215 | *.ldf 216 | 217 | # Business Intelligence projects 218 | *.rdl.data 219 | *.bim.layout 220 | *.bim_*.settings 221 | 222 | # Microsoft Fakes 223 | FakesAssemblies/ 224 | 225 | # GhostDoc plugin setting file 226 | *.GhostDoc.xml 227 | 228 | # Node.js Tools for Visual Studio 229 | .ntvs_analysis.dat 230 | 231 | # Visual Studio 6 build log 232 | *.plg 233 | 234 | # Visual Studio 6 workspace options file 235 | *.opt 236 | 237 | # Visual Studio LightSwitch build output 238 | **/*.HTMLClient/GeneratedArtifacts 239 | **/*.DesktopClient/GeneratedArtifacts 240 | **/*.DesktopClient/ModelManifest.xml 241 | **/*.Server/GeneratedArtifacts 242 | **/*.Server/ModelManifest.xml 243 | _Pvt_Extensions 244 | 245 | # Paket dependency manager 246 | .paket/paket.exe 247 | paket-files/ 248 | 249 | # FAKE - F# Make 250 | .fake/ 251 | 252 | # JetBrains Rider 253 | .idea/ 254 | *.sln.iml 255 | 256 | # CodeRush 257 | .cr/ 258 | 259 | # Python Tools for Visual Studio (PTVS) 260 | __pycache__/ 261 | *.pyc -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /WZDumper/About.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 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /WZDumper/MainForm.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 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 36, 21 122 | 123 | 124 | 157, 24 125 | 126 | -------------------------------------------------------------------------------- /WzDumper.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | AnyCPU 6 | 9.0.21022 7 | 2.0 8 | {E252897F-9BF1-4AA3-AFD9-E0DF259B453C} 9 | WinExe 10 | Properties 11 | WzDumper 12 | WZ Dumper 13 | v4.7.2 14 | 512 15 | false 16 | 17 | 18 | 3.5 19 | 20 | 21 | publish\ 22 | true 23 | Disk 24 | false 25 | Foreground 26 | 7 27 | Days 28 | false 29 | false 30 | true 31 | 0 32 | 1.0.0.%2a 33 | false 34 | true 35 | 36 | 37 | true 38 | full 39 | false 40 | bin\Debug\ 41 | DEBUG;TRACE 42 | prompt 43 | 4 44 | AllRules.ruleset 45 | false 46 | 47 | 48 | pdbonly 49 | true 50 | bin\Release\ 51 | 52 | 53 | prompt 54 | 4 55 | 56 | 57 | AllRules.ruleset 58 | false 59 | 60 | 61 | false 62 | 63 | 64 | 65 | 66 | 67 | false 68 | 69 | 70 | false 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | Form 85 | 86 | 87 | About.cs 88 | 89 | 90 | Form 91 | 92 | 93 | MainForm.cs 94 | 95 | 96 | Component 97 | 98 | 99 | 100 | 101 | 102 | About.cs 103 | Designer 104 | 105 | 106 | MainForm.cs 107 | Designer 108 | 109 | 110 | ResXFileCodeGenerator 111 | Resources.Designer.cs 112 | Designer 113 | 114 | 115 | True 116 | Resources.resx 117 | True 118 | 119 | 120 | 121 | SettingsSingleFileGenerator 122 | Settings.Designer.cs 123 | 124 | 125 | True 126 | Settings.settings 127 | True 128 | 129 | 130 | 131 | 132 | False 133 | .NET Framework 2.0 %28x86%29 134 | false 135 | 136 | 137 | False 138 | .NET Framework 3.0 %28x86%29 139 | false 140 | 141 | 142 | False 143 | .NET Framework 3.5 144 | false 145 | 146 | 147 | False 148 | .NET Framework 3.5 SP1 149 | true 150 | 151 | 152 | False 153 | Windows Installer 3.1 154 | true 155 | 156 | 157 | 158 | 159 | {28aab36d-942e-4476-a000-0e9de380f390} 160 | MapleLib 161 | 162 | 163 | 164 | 171 | -------------------------------------------------------------------------------- /WZDumper/WzXml.cs: -------------------------------------------------------------------------------- 1 | using MapleLib.WzLib; 2 | using MapleLib.WzLib.WzProperties; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Drawing.Imaging; 6 | using System.Globalization; 7 | using System.IO; 8 | using System.Linq; 9 | using System.Runtime.InteropServices; 10 | using System.Text; 11 | using System.Threading; 12 | using System.Xml; 13 | 14 | namespace WzDumper { 15 | public class WzXml { 16 | [DllImport("kernel32.dll")] 17 | public static extern uint GetLastError(); 18 | [DllImport("Kernel32.dll", CharSet = CharSet.Unicode)] 19 | static extern bool CreateHardLink(string lpFileName, string lpExistingFileName, IntPtr lpSecurityAttributes); 20 | [DllImport("kernel32.dll", EntryPoint = "CreateSymbolicLinkW", CharSet = CharSet.Unicode, SetLastError = true)] 21 | static extern bool CreateSymbolicLink(string lpSymlinkFileName, string lpTargetFileName, int dwFlags); 22 | 23 | public WzXml(MainForm form, string parentPath, string wzStartingDir, bool extractAll, LinkType type) { 24 | Form = form; 25 | ExtractPath = parentPath; 26 | WzFolderName = wzStartingDir; 27 | IncludePngMp3 = extractAll; 28 | LinkType = type; 29 | Token = form.CancelSource.Token; 30 | } 31 | 32 | public MainForm Form { get; } 33 | public string ExtractPath { get; } 34 | public string WzFolderName { get; } 35 | public bool IncludePngMp3 { get; } 36 | public LinkType LinkType { get; } 37 | public static XmlWriterSettings XmlSettings { get; set; } = new XmlWriterSettings { 38 | Indent = true, 39 | IndentChars = " ", 40 | Encoding = Encoding.UTF8 41 | }; 42 | public CancellationToken Token { get; } 43 | public static CultureInfo Cul { get; } = CultureInfo.CreateSpecificCulture("en-US"); 44 | public static char[] InvalidFileChars { get; } = Path.GetInvalidFileNameChars(); 45 | public Dictionary InvalidDirs { get; set; } = new Dictionary(); 46 | public string CurrentImageDir { get; set; } 47 | 48 | public void DumpDir(WzDirectory mainDir) { 49 | DumpDir(mainDir, WzFolderName); 50 | InvalidDirs.Clear(); 51 | InvalidDirs = null; 52 | } 53 | 54 | public void DumpDir(WzDirectory mainDir, string wzDir) { 55 | foreach (var directory2 in mainDir.WzDirectories) { 56 | var dirName = Path.Combine(wzDir, directory2.Name); 57 | CreateDirectory(ref dirName); 58 | DumpDir(directory2, dirName); 59 | } 60 | foreach (var image in mainDir.WzImages) { 61 | if (Token.IsCancellationRequested) 62 | return; 63 | DumpImage(image, wzDir); 64 | } 65 | } 66 | 67 | public void DumpImage(WzImage img, string mainDir) { 68 | Form.UpdateToolstripStatus("Dumping " + img.Name + ".xml to " + mainDir); 69 | using (StreamWriter sw = new StreamWriter(ExtractPath + "\\" + mainDir + "\\" + img.Name + ".xml")) { 70 | using (XmlWriter xmlWriter = XmlWriter.Create(sw, XmlSettings)) { 71 | xmlWriter.WriteStartDocument(true); 72 | xmlWriter.WriteStartElement("imgdir"); 73 | xmlWriter.WriteStartAttribute("name"); 74 | xmlWriter.WriteValue(img.Name); 75 | CurrentImageDir = Path.Combine(mainDir, img.Name); 76 | DumpData(xmlWriter, img.WzProperties, CurrentImageDir); 77 | xmlWriter.WriteEndElement(); 78 | xmlWriter.WriteEndDocument(); 79 | } 80 | } 81 | img.PartialDispose(); 82 | } 83 | 84 | private void DumpData(XmlWriter tw, IEnumerable props, string wzPath) { 85 | foreach (var property in props.Where(property => property != null)) { 86 | switch (property.PropertyType) { 87 | case WzPropertyType.ByteFloat: 88 | var byteFloatProp = (WzByteFloatProperty)property; 89 | tw.WriteStartElement("float"); 90 | tw.WriteStartAttribute("name"); 91 | tw.WriteValue(byteFloatProp.Name); 92 | tw.WriteStartAttribute("value"); 93 | tw.WriteValue(byteFloatProp.Value.ToString("0.0######", Cul)); 94 | tw.WriteEndElement(); 95 | break; 96 | case WzPropertyType.Canvas: 97 | var canvasProp = (WzCanvasProperty)property; 98 | if (IncludePngMp3) { 99 | DumpCanvasProp(wzPath, canvasProp, null, false); 100 | } 101 | tw.WriteStartElement("canvas"); 102 | tw.WriteStartAttribute("name"); 103 | tw.WriteValue(canvasProp.Name); 104 | tw.WriteStartAttribute("width"); 105 | tw.WriteValue(canvasProp.PngProperty.Width); 106 | tw.WriteStartAttribute("height"); 107 | tw.WriteValue(canvasProp.PngProperty.Height); 108 | DumpData(tw, canvasProp.WzProperties, wzPath); 109 | tw.WriteEndElement(); 110 | break; 111 | case WzPropertyType.CompressedInt: 112 | var compressedIntProp = (WzCompressedIntProperty)property; 113 | tw.WriteStartElement("int"); 114 | tw.WriteStartAttribute("name"); 115 | tw.WriteValue(compressedIntProp.Name); 116 | tw.WriteStartAttribute("value"); 117 | tw.WriteValue(compressedIntProp.Value); 118 | tw.WriteEndElement(); 119 | break; 120 | case WzPropertyType.CompressedLong: 121 | var compressedLongProp = (WzCompressedLongProperty)property; 122 | tw.WriteStartElement("int"); 123 | tw.WriteStartAttribute("name"); 124 | tw.WriteValue(compressedLongProp.Name); 125 | tw.WriteStartAttribute("value"); 126 | tw.WriteValue(compressedLongProp.Value); 127 | tw.WriteEndElement(); 128 | break; 129 | case WzPropertyType.Convex: 130 | var convexProp = (WzConvexProperty)property; 131 | tw.WriteStartElement("extended"); 132 | tw.WriteStartAttribute("name"); 133 | tw.WriteValue(convexProp.Name); 134 | DumpData(tw, convexProp.WzProperties, wzPath); 135 | tw.WriteEndElement(); 136 | break; 137 | case WzPropertyType.Double: 138 | var doubleProp = (WzDoubleProperty)property; 139 | tw.WriteStartElement("double"); 140 | tw.WriteStartAttribute("name"); 141 | tw.WriteValue(doubleProp.Name); 142 | tw.WriteStartAttribute("value"); 143 | tw.WriteValue(doubleProp.Value.ToString("0.0###############", Cul)); 144 | tw.WriteEndElement(); 145 | break; 146 | case WzPropertyType.Null: 147 | var nullProp = (WzNullProperty)property; 148 | tw.WriteStartElement("null"); 149 | tw.WriteStartAttribute("name"); 150 | tw.WriteValue(nullProp.Name); 151 | tw.WriteEndElement(); 152 | break; 153 | case WzPropertyType.RawData: 154 | var rawDataProp = (WzRawDataProperty)property; 155 | tw.WriteStartElement("raw"); 156 | tw.WriteStartAttribute("name"); 157 | tw.WriteValue(rawDataProp.Name); 158 | tw.WriteEndElement(); 159 | /*if (IncludePngMp3) { 160 | WriteRawData(wzPath, rawDataProp, null, false, null); 161 | }*/ 162 | break; 163 | case WzPropertyType.Short: 164 | var shortProp = (WzShortProperty)property; 165 | tw.WriteStartElement("short"); 166 | tw.WriteStartAttribute("name"); 167 | tw.WriteValue(shortProp.Name); 168 | tw.WriteStartAttribute("value"); 169 | tw.WriteValue(shortProp.Value); 170 | tw.WriteEndElement(); 171 | break; 172 | case WzPropertyType.Sound: 173 | var soundProp = (WzSoundProperty)property; 174 | tw.WriteStartElement("sound"); 175 | tw.WriteStartAttribute("name"); 176 | tw.WriteValue(soundProp.Name); 177 | tw.WriteEndElement(); 178 | if (IncludePngMp3) { 179 | WriteSoundProp(wzPath, soundProp, null, false, null); 180 | } 181 | break; 182 | case WzPropertyType.String: 183 | var stringProp = (WzStringProperty)property; 184 | tw.WriteStartElement("string"); 185 | tw.WriteStartAttribute("name"); 186 | tw.WriteValue(stringProp.Name); 187 | tw.WriteStartAttribute("value"); 188 | tw.WriteValue(stringProp.Value); 189 | tw.WriteEndElement(); 190 | break; 191 | case WzPropertyType.SubProperty: 192 | var subProp = (WzSubProperty)property; 193 | tw.WriteStartElement("imgdir"); 194 | tw.WriteStartAttribute("name"); 195 | tw.WriteValue(subProp.Name); 196 | DumpData(tw, subProp.WzProperties, Path.Combine(wzPath, subProp.Name)); 197 | tw.WriteEndElement(); 198 | break; 199 | case WzPropertyType.UOL: 200 | var uolProp = (WzUOLProperty)property; 201 | tw.WriteStartElement("uol"); 202 | tw.WriteStartAttribute("name"); 203 | tw.WriteValue(uolProp.Name); 204 | tw.WriteStartAttribute("value"); 205 | tw.WriteValue(uolProp.Value); 206 | tw.WriteEndElement(); 207 | if (IncludePngMp3) { 208 | var obj = uolProp.LinkValue; 209 | if (obj != null) { 210 | DumpFromUOL(uolProp, obj, wzPath); 211 | } 212 | } 213 | break; 214 | case WzPropertyType.Vector: 215 | var vectorProp = (WzVectorProperty)property; 216 | tw.WriteStartElement("vector"); 217 | tw.WriteStartAttribute("name"); 218 | tw.WriteValue(vectorProp.Name); 219 | tw.WriteStartAttribute("x"); 220 | tw.WriteValue(vectorProp.X.Value); 221 | tw.WriteStartAttribute("y"); 222 | tw.WriteValue(vectorProp.Y.Value); 223 | tw.WriteEndElement(); 224 | break; 225 | } 226 | } 227 | } 228 | 229 | private void DumpFromUOL(AWzObject uolProp, AWzImageProperty obj, string wzPath, bool copyName = false) { 230 | var name = copyName ? obj.Name : uolProp.Name; 231 | switch (obj.PropertyType) { 232 | case WzPropertyType.Canvas: 233 | var uolPngProp = (WzCanvasProperty)obj; 234 | DumpCanvasProp(wzPath, uolPngProp, uolProp, copyName); 235 | break; 236 | case WzPropertyType.SubProperty: 237 | var uolSubProp = (WzSubProperty)obj; 238 | var subDir = Path.Combine(wzPath, CleanFileName(name)); 239 | if (LinkType == LinkType.Symbolic) { 240 | string linkPath = Path.Combine(ExtractPath, subDir); 241 | string targetDir = Path.Combine(WzFolderName, uolSubProp.FullPath.Substring(uolSubProp.FullPath.IndexOf("\\", StringComparison.OrdinalIgnoreCase) + 1)); 242 | Directory.CreateDirectory(Directory.GetParent(linkPath).FullName); 243 | CreateDirectory(ref targetDir); 244 | bool res = CreateSymbolicLink(linkPath, Path.Combine(ExtractPath, targetDir), 1); 245 | if (!res) { 246 | uint error = GetLastError(); 247 | if (error == 183) { 248 | File.Delete(linkPath); 249 | CreateSymbolicLink(linkPath, Path.Combine(ExtractPath, targetDir), 1); 250 | } else 251 | Form.UpdateTextBoxInfo(Form.InfoTextBox, "Error creating link: " + GetLastError() + " - " + linkPath + " -> " + targetDir, true); 252 | } 253 | } else { 254 | foreach (var file in uolSubProp.WzProperties) { 255 | DumpFromUOL(uolProp, file, subDir, true); 256 | } 257 | } 258 | break; 259 | case WzPropertyType.Sound: 260 | name = CleanFileName(name); 261 | var uolSoundProp = (WzSoundProperty)obj; 262 | CreateDirectory(ref wzPath); 263 | if (LinkType != LinkType.Copy) { 264 | string linkPath = Path.Combine(ExtractPath, wzPath, name + ".mp3"); 265 | int lastIndex = uolSoundProp.FullPath.LastIndexOf("\\"); 266 | int startIndex = uolSoundProp.FullPath.IndexOf("\\", StringComparison.OrdinalIgnoreCase) + 1; 267 | string targetPath = Path.Combine(WzFolderName, uolSoundProp.FullPath.Substring(startIndex, uolSoundProp.FullPath.Length - uolSoundProp.FullPath.Substring(lastIndex).Length - startIndex)); 268 | string targetFile = uolSoundProp.FullPath.Substring(lastIndex + 1) + ".mp3"; 269 | string fullPath = SanitizeTargetPath(targetPath, targetFile); 270 | FileInfo file = new FileInfo(fullPath); 271 | if (!File.Exists(fullPath)) { 272 | file.Directory.Create(); 273 | WriteSoundProp(wzPath, uolSoundProp, uolProp, copyName, fullPath); 274 | } 275 | bool res = LinkType == LinkType.Symbolic ? CreateSymbolicLink(linkPath, fullPath, 0) : CreateHardLink(linkPath, fullPath, IntPtr.Zero); 276 | if (!res) { 277 | uint error = GetLastError(); 278 | if (error == 1142) 279 | WriteSoundProp(wzPath, uolSoundProp, uolProp, copyName, null); 280 | else if (error == 183) { 281 | File.Delete(linkPath); 282 | _ = LinkType == LinkType.Symbolic ? CreateSymbolicLink(linkPath, fullPath, 0) : CreateHardLink(linkPath, fullPath, IntPtr.Zero); 283 | } else 284 | Form.UpdateTextBoxInfo(Form.InfoTextBox, "Error creating link: " + error + " - " + linkPath + " -> " + fullPath, true); 285 | } 286 | } else { 287 | WriteSoundProp(wzPath, uolSoundProp, uolProp, copyName, null); 288 | } 289 | break; 290 | case WzPropertyType.UOL: 291 | var subUOL = (WzUOLProperty)obj; 292 | var uolVal = subUOL.LinkValue; 293 | if (uolVal != null) { 294 | DumpFromUOL(subUOL, uolVal, wzPath, false); 295 | } 296 | break; 297 | } 298 | } 299 | 300 | private void CreateDirectory(ref string directory) { 301 | if (InvalidDirs.ContainsKey(directory)) 302 | InvalidDirs.TryGetValue(directory, out directory); 303 | string folderPath = Path.Combine(ExtractPath, directory); 304 | if (!Directory.Exists(folderPath)) { 305 | try { 306 | Directory.CreateDirectory(folderPath); 307 | } catch (DirectoryNotFoundException) { 308 | InvalidDirs.Add(directory, directory += "_"); 309 | folderPath = Path.Combine(ExtractPath, directory); 310 | if (!Directory.Exists(folderPath)) 311 | Directory.CreateDirectory(folderPath); 312 | } catch (NotSupportedException) { 313 | SanitizePath(ref directory); 314 | folderPath = Path.Combine(ExtractPath, directory); 315 | if (!Directory.Exists(folderPath)) 316 | Directory.CreateDirectory(folderPath); 317 | } catch (ArgumentException) { 318 | SanitizePath(ref directory); 319 | folderPath = Path.Combine(ExtractPath, directory); 320 | if (!Directory.Exists(folderPath)) 321 | Directory.CreateDirectory(folderPath); 322 | } 323 | } 324 | } 325 | 326 | private static string CleanFileName(string fileName) { 327 | return InvalidFileChars.Aggregate(fileName, (current, c) => current.Replace(c.ToString(), "_")); 328 | } 329 | 330 | private void SanitizePath(ref string directory) { 331 | string[] splitPath = directory.Trim().Split(new char[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }); 332 | string newDirectory = String.Empty; 333 | foreach (string partPath in splitPath) { 334 | newDirectory += CleanFileName(partPath) + Path.DirectorySeparatorChar; 335 | } 336 | InvalidDirs.Add(directory, newDirectory); 337 | directory = newDirectory; 338 | } 339 | 340 | private string SanitizeTargetPath(string path, string name) { 341 | path = path.Replace("/", "\\"); 342 | CreateDirectory(ref path); 343 | return Path.Combine(ExtractPath, path, CleanFileName(name)); 344 | } 345 | 346 | private void DumpCanvasProp(string wzPath, WzCanvasProperty canvasProp, AWzObject uol, bool uolDirCopy) { 347 | string fileName = CleanFileName(uol != null && !uolDirCopy ? uol.Name : canvasProp.Name); 348 | if (LinkType != LinkType.Copy && !(string.IsNullOrEmpty(canvasProp.Outlink) && string.IsNullOrEmpty(canvasProp.Inlink) && uol == null)) { 349 | string targetPath, targetFile; 350 | if (!string.IsNullOrEmpty(canvasProp.Inlink)) { 351 | int lastIndex = canvasProp.Inlink.LastIndexOf("/"); 352 | targetPath = Path.Combine(CurrentImageDir, canvasProp.Inlink.Substring(0, lastIndex)); 353 | targetFile = canvasProp.Inlink.Substring(lastIndex + 1) + ".png"; 354 | } else if (!string.IsNullOrEmpty(canvasProp.Outlink)) { 355 | int lastIndex = canvasProp.Outlink.LastIndexOf("/"); 356 | int startIndex = canvasProp.Outlink.IndexOf("/", StringComparison.OrdinalIgnoreCase) + 1; 357 | targetPath = Path.Combine(WzFolderName, canvasProp.Outlink.Substring(startIndex, canvasProp.Outlink.Length - canvasProp.Outlink.Substring(lastIndex).Length - startIndex)); 358 | targetFile = canvasProp.Outlink.Substring(lastIndex + 1) + ".png"; 359 | } else { 360 | int lastIndex = canvasProp.FullPath.LastIndexOf("\\"); 361 | int startIndex = canvasProp.FullPath.IndexOf("\\", StringComparison.OrdinalIgnoreCase) + 1; 362 | targetPath = Path.Combine(WzFolderName, canvasProp.FullPath.Substring(startIndex, canvasProp.FullPath.Length - canvasProp.FullPath.Substring(lastIndex).Length - startIndex)); 363 | targetFile = canvasProp.FullPath.Substring(lastIndex + 1) + ".png"; 364 | } 365 | string fullTargetPath = SanitizeTargetPath(targetPath, targetFile); 366 | FileInfo file = new FileInfo(fullTargetPath); 367 | bool createLink = true; 368 | if (!File.Exists(fullTargetPath)) { 369 | createLink = WritePng(wzPath, fileName, fullTargetPath, canvasProp, file); 370 | } 371 | if (createLink) { 372 | CreateDirectory(ref wzPath); 373 | string newFilePath = Path.Combine(ExtractPath, wzPath, fileName + ".png"); 374 | bool res = LinkType == LinkType.Symbolic ? CreateSymbolicLink(newFilePath, fullTargetPath, 0) : CreateHardLink(newFilePath, fullTargetPath, IntPtr.Zero); 375 | if (!res) { 376 | uint error = GetLastError(); 377 | if (error == 1142) // max links reached for file, fallback to copy mode 378 | WritePng(wzPath, fileName, newFilePath, canvasProp); 379 | else if (error == 183) { // link already exists, recreate in case old link was diff 380 | File.Delete(newFilePath); 381 | _ = LinkType == LinkType.Symbolic ? CreateSymbolicLink(newFilePath, fullTargetPath, 0) : CreateHardLink(newFilePath, fullTargetPath, IntPtr.Zero); 382 | } else 383 | Form.UpdateTextBoxInfo(Form.InfoTextBox, "Error creating link: " + error + " - " + newFilePath + " -> " + fullTargetPath, true); 384 | } 385 | } 386 | } else { 387 | WritePng(wzPath, fileName, null, canvasProp); 388 | } 389 | } 390 | 391 | /*private void WriteRawData(string wzPath, WzRawDataProperty rawDataProp, AWzObject uol, bool uolDirCopy, string overridePath) { 392 | string fileName = CleanFileName(uol != null && !uolDirCopy ? uol.Name : rawDataProp.Name); 393 | if (overridePath == null) 394 | CreateDirectory(ref wzPath); 395 | string newFilePath = overridePath ?? Path.Combine(ExtractPath, wzPath, fileName); 396 | Form.UpdateToolstripStatus("Dumping " + rawDataProp.Name + " to " + newFilePath); 397 | using (var stream = new FileStream(newFilePath, FileMode.Create, FileAccess.Write)) { 398 | stream.Write(rawDataProp.GetBytes(), 0, rawDataProp.GetBytes().Length); 399 | } 400 | }*/ 401 | 402 | private void WriteSoundProp(string wzPath, WzSoundProperty soundProp, AWzObject uol, bool uolDirCopy, string overridePath) { 403 | string fileName = CleanFileName(uol != null && !uolDirCopy ? uol.Name : soundProp.Name); 404 | if (overridePath == null) 405 | CreateDirectory(ref wzPath); 406 | string ext = soundProp.GetExtension(); 407 | string newFilePath = overridePath ?? Path.Combine(ExtractPath, wzPath, fileName + ext); 408 | Form.UpdateToolstripStatus("Dumping " + soundProp.Name + ext + " to " + newFilePath); 409 | using (var stream = new FileStream(newFilePath, FileMode.Create, FileAccess.Write)) { 410 | stream.Write(soundProp.GetBytes(), 0, soundProp.GetBytes().Length); 411 | } 412 | } 413 | 414 | private bool WritePng(string wzPath, string fileName, string filePath, WzCanvasProperty canvasProp, FileInfo overrideFile = null) { 415 | Form.UpdateToolstripStatus("Dumping " + fileName + ".png to " + wzPath); 416 | while (!string.IsNullOrEmpty(canvasProp.Inlink) || !string.IsNullOrEmpty(canvasProp.Outlink)) { 417 | if (!string.IsNullOrEmpty(canvasProp.Inlink)) { 418 | if (canvasProp.InlinkValue == null) 419 | return false; 420 | canvasProp = canvasProp.InlinkValue; 421 | } else if (!string.IsNullOrEmpty(canvasProp.Outlink)) { 422 | if (canvasProp.OutlinkValue == null) 423 | return false; 424 | canvasProp = canvasProp.OutlinkValue; 425 | } 426 | } 427 | if (canvasProp != null) { 428 | CreateDirectory(ref wzPath); 429 | overrideFile?.Directory.Create(); 430 | if (filePath == null) 431 | filePath = Path.Combine(ExtractPath, wzPath, fileName + ".png"); 432 | using (var myFileOut = new FileStream(filePath, FileMode.Create)) { 433 | if (canvasProp.PngProperty.GetPNG() == null) 434 | Form.UpdateTextBoxInfo(Form.InfoTextBox, "Error Dumping " + fileName + ".png to " + wzPath, true); 435 | else 436 | canvasProp.PngProperty.GetPNG().Save(myFileOut, ImageFormat.Png); 437 | } 438 | return true; 439 | } 440 | return false; 441 | } 442 | } 443 | } -------------------------------------------------------------------------------- /WZDumper/MainForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace WzDumper { 2 | partial class MainForm { 3 | /// 4 | /// Required designer variable. 5 | /// 6 | private System.ComponentModel.IContainer components = null; 7 | 8 | /// 9 | /// Clean up any resources being used. 10 | /// 11 | /// true if managed resources should be disposed; otherwise, false. 12 | protected override void Dispose(bool disposing) { 13 | if (disposing && (components != null)) { 14 | components.Dispose(); 15 | } 16 | if (CancelSource != null) 17 | CancelSource.Dispose(); 18 | base.Dispose(disposing); 19 | } 20 | 21 | #region Windows Form Designer generated code 22 | 23 | /// 24 | /// Required method for Designer support - do not modify 25 | /// the contents of this method with the code editor. 26 | /// 27 | private void InitializeComponent() { 28 | this.SelectWzFileButton = new System.Windows.Forms.Button(); 29 | this.DumpWzButton = new System.Windows.Forms.Button(); 30 | this.Info = new System.Windows.Forms.TextBox(); 31 | this.includePngMp3Box = new System.Windows.Forms.CheckBox(); 32 | this.statusStrip1 = new System.Windows.Forms.StatusStrip(); 33 | this.CancelOpButton = new System.Windows.Forms.Button(); 34 | this.versionBox = new System.Windows.Forms.TextBox(); 35 | this.label2 = new System.Windows.Forms.Label(); 36 | this.MapleVersionComboBox = new System.Windows.Forms.ComboBox(); 37 | this.label3 = new System.Windows.Forms.Label(); 38 | this.WZFileTB = new System.Windows.Forms.TextBox(); 39 | this.outputFolderTB = new System.Windows.Forms.TextBox(); 40 | this.label4 = new System.Windows.Forms.Label(); 41 | this.label5 = new System.Windows.Forms.Label(); 42 | this.openFolderButton = new System.Windows.Forms.Button(); 43 | this.menuStrip1 = new System.Windows.Forms.MenuStrip(); 44 | this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 45 | this.clearInfoToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 46 | this.exitToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 47 | this.aboutToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); 48 | this.aboutToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); 49 | this.includeVersionInFolderBox = new System.Windows.Forms.CheckBox(); 50 | this.multiThreadCheckBox = new System.Windows.Forms.CheckBox(); 51 | this.extractorThreadsNum = new System.Windows.Forms.NumericUpDown(); 52 | this.extractorThreadsLabel = new System.Windows.Forms.Label(); 53 | this.SelectWzFolder = new System.Windows.Forms.Button(); 54 | this.SelectExtractDestination = new System.Windows.Forms.Button(); 55 | this.LinkTypeLabel = new System.Windows.Forms.Label(); 56 | this.LinkTypeComboBox = new System.Windows.Forms.ComboBox(); 57 | this.toolStripStatusLabel1 = new WzDumper.SafeToolStripLabel(); 58 | this.statusStrip1.SuspendLayout(); 59 | this.menuStrip1.SuspendLayout(); 60 | ((System.ComponentModel.ISupportInitialize)(this.extractorThreadsNum)).BeginInit(); 61 | this.SuspendLayout(); 62 | // 63 | // SelectWzFileButton 64 | // 65 | this.SelectWzFileButton.Anchor = System.Windows.Forms.AnchorStyles.Bottom; 66 | this.SelectWzFileButton.Location = new System.Drawing.Point(537, 294); 67 | this.SelectWzFileButton.Name = "SelectWzFileButton"; 68 | this.SelectWzFileButton.Size = new System.Drawing.Size(67, 23); 69 | this.SelectWzFileButton.TabIndex = 0; 70 | this.SelectWzFileButton.Text = "Select File"; 71 | this.SelectWzFileButton.UseVisualStyleBackColor = true; 72 | this.SelectWzFileButton.Click += new System.EventHandler(this.SelectWzFile); 73 | // 74 | // DumpWzButton 75 | // 76 | this.DumpWzButton.Anchor = System.Windows.Forms.AnchorStyles.Bottom; 77 | this.DumpWzButton.Enabled = false; 78 | this.DumpWzButton.Location = new System.Drawing.Point(537, 354); 79 | this.DumpWzButton.Name = "DumpWzButton"; 80 | this.DumpWzButton.Size = new System.Drawing.Size(72, 23); 81 | this.DumpWzButton.TabIndex = 5; 82 | this.DumpWzButton.Text = "Dump"; 83 | this.DumpWzButton.UseVisualStyleBackColor = true; 84 | this.DumpWzButton.Click += new System.EventHandler(this.DumpFile); 85 | // 86 | // Info 87 | // 88 | this.Info.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 89 | | System.Windows.Forms.AnchorStyles.Left) 90 | | System.Windows.Forms.AnchorStyles.Right))); 91 | this.Info.BackColor = System.Drawing.SystemColors.ControlLightLight; 92 | this.Info.Location = new System.Drawing.Point(12, 29); 93 | this.Info.Multiline = true; 94 | this.Info.Name = "Info"; 95 | this.Info.ReadOnly = true; 96 | this.Info.ScrollBars = System.Windows.Forms.ScrollBars.Both; 97 | this.Info.Size = new System.Drawing.Size(680, 259); 98 | this.Info.TabIndex = 9; 99 | this.Info.TabStop = false; 100 | // 101 | // includePngMp3Box 102 | // 103 | this.includePngMp3Box.Anchor = System.Windows.Forms.AnchorStyles.Bottom; 104 | this.includePngMp3Box.AutoSize = true; 105 | this.includePngMp3Box.Location = new System.Drawing.Point(12, 387); 106 | this.includePngMp3Box.Name = "includePngMp3Box"; 107 | this.includePngMp3Box.Size = new System.Drawing.Size(149, 17); 108 | this.includePngMp3Box.TabIndex = 3; 109 | this.includePngMp3Box.Text = "Include Images and MP3s"; 110 | this.includePngMp3Box.UseVisualStyleBackColor = true; 111 | this.includePngMp3Box.CheckedChanged += new System.EventHandler(this.IncludePngMp3Box_CheckedChanged); 112 | // 113 | // statusStrip1 114 | // 115 | this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { 116 | this.toolStripStatusLabel1}); 117 | this.statusStrip1.Location = new System.Drawing.Point(0, 439); 118 | this.statusStrip1.Name = "statusStrip1"; 119 | this.statusStrip1.Size = new System.Drawing.Size(704, 22); 120 | this.statusStrip1.TabIndex = 17; 121 | this.statusStrip1.Text = "statusStrip1"; 122 | // 123 | // CancelOpButton 124 | // 125 | this.CancelOpButton.Anchor = System.Windows.Forms.AnchorStyles.Bottom; 126 | this.CancelOpButton.Enabled = false; 127 | this.CancelOpButton.Location = new System.Drawing.Point(615, 354); 128 | this.CancelOpButton.Name = "CancelOpButton"; 129 | this.CancelOpButton.Size = new System.Drawing.Size(60, 23); 130 | this.CancelOpButton.TabIndex = 7; 131 | this.CancelOpButton.Text = "Cancel"; 132 | this.CancelOpButton.UseVisualStyleBackColor = true; 133 | this.CancelOpButton.Click += new System.EventHandler(this.CancelOperation); 134 | // 135 | // versionBox 136 | // 137 | this.versionBox.Anchor = System.Windows.Forms.AnchorStyles.Bottom; 138 | this.versionBox.Enabled = false; 139 | this.versionBox.Location = new System.Drawing.Point(345, 355); 140 | this.versionBox.MaxLength = 5; 141 | this.versionBox.Name = "versionBox"; 142 | this.versionBox.ReadOnly = true; 143 | this.versionBox.Size = new System.Drawing.Size(42, 20); 144 | this.versionBox.TabIndex = 2; 145 | // 146 | // label2 147 | // 148 | this.label2.Anchor = System.Windows.Forms.AnchorStyles.Bottom; 149 | this.label2.AutoSize = true; 150 | this.label2.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F); 151 | this.label2.Location = new System.Drawing.Point(9, 360); 152 | this.label2.Name = "label2"; 153 | this.label2.Size = new System.Drawing.Size(60, 13); 154 | this.label2.TabIndex = 15; 155 | this.label2.Text = "Encryption:"; 156 | // 157 | // MapleVersionComboBox 158 | // 159 | this.MapleVersionComboBox.Anchor = System.Windows.Forms.AnchorStyles.Bottom; 160 | this.MapleVersionComboBox.FormattingEnabled = true; 161 | this.MapleVersionComboBox.Items.AddRange(new object[] { 162 | "None", 163 | "GMS (v0.56-0.116)", 164 | "EMS/MSEA"}); 165 | this.MapleVersionComboBox.Location = new System.Drawing.Point(76, 356); 166 | this.MapleVersionComboBox.Name = "MapleVersionComboBox"; 167 | this.MapleVersionComboBox.Size = new System.Drawing.Size(122, 21); 168 | this.MapleVersionComboBox.TabIndex = 1; 169 | this.MapleVersionComboBox.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.MapleVersionComboBoxKeyPress); 170 | // 171 | // label3 172 | // 173 | this.label3.Anchor = System.Windows.Forms.AnchorStyles.Bottom; 174 | this.label3.AutoSize = true; 175 | this.label3.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F); 176 | this.label3.Location = new System.Drawing.Point(228, 360); 177 | this.label3.Name = "label3"; 178 | this.label3.Size = new System.Drawing.Size(111, 13); 179 | this.label3.TabIndex = 16; 180 | this.label3.Text = "Detected File Version:"; 181 | // 182 | // WZFileTB 183 | // 184 | this.WZFileTB.Anchor = System.Windows.Forms.AnchorStyles.Bottom; 185 | this.WZFileTB.BackColor = System.Drawing.SystemColors.ControlLightLight; 186 | this.WZFileTB.Location = new System.Drawing.Point(76, 295); 187 | this.WZFileTB.Name = "WZFileTB"; 188 | this.WZFileTB.ReadOnly = true; 189 | this.WZFileTB.Size = new System.Drawing.Size(455, 20); 190 | this.WZFileTB.TabIndex = 10; 191 | // 192 | // outputFolderTB 193 | // 194 | this.outputFolderTB.Anchor = System.Windows.Forms.AnchorStyles.Bottom; 195 | this.outputFolderTB.BackColor = System.Drawing.SystemColors.ControlLightLight; 196 | this.outputFolderTB.Location = new System.Drawing.Point(76, 325); 197 | this.outputFolderTB.Name = "outputFolderTB"; 198 | this.outputFolderTB.ReadOnly = true; 199 | this.outputFolderTB.Size = new System.Drawing.Size(455, 20); 200 | this.outputFolderTB.TabIndex = 11; 201 | // 202 | // label4 203 | // 204 | this.label4.Anchor = System.Windows.Forms.AnchorStyles.Bottom; 205 | this.label4.AutoSize = true; 206 | this.label4.Location = new System.Drawing.Point(9, 298); 207 | this.label4.Name = "label4"; 208 | this.label4.Size = new System.Drawing.Size(60, 13); 209 | this.label4.TabIndex = 13; 210 | this.label4.Text = "File/Folder:"; 211 | // 212 | // label5 213 | // 214 | this.label5.Anchor = System.Windows.Forms.AnchorStyles.Bottom; 215 | this.label5.AutoSize = true; 216 | this.label5.Location = new System.Drawing.Point(27, 328); 217 | this.label5.Name = "label5"; 218 | this.label5.Size = new System.Drawing.Size(42, 13); 219 | this.label5.TabIndex = 14; 220 | this.label5.Text = "Output:"; 221 | // 222 | // openFolderButton 223 | // 224 | this.openFolderButton.Anchor = System.Windows.Forms.AnchorStyles.Bottom; 225 | this.openFolderButton.Enabled = false; 226 | this.openFolderButton.Location = new System.Drawing.Point(621, 324); 227 | this.openFolderButton.Name = "openFolderButton"; 228 | this.openFolderButton.Size = new System.Drawing.Size(53, 23); 229 | this.openFolderButton.TabIndex = 12; 230 | this.openFolderButton.Text = "Open"; 231 | this.openFolderButton.UseVisualStyleBackColor = true; 232 | this.openFolderButton.Click += new System.EventHandler(this.OpenFolder); 233 | // 234 | // menuStrip1 235 | // 236 | this.menuStrip1.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None; 237 | this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { 238 | this.fileToolStripMenuItem, 239 | this.aboutToolStripMenuItem}); 240 | this.menuStrip1.Location = new System.Drawing.Point(0, 0); 241 | this.menuStrip1.Name = "menuStrip1"; 242 | this.menuStrip1.RenderMode = System.Windows.Forms.ToolStripRenderMode.System; 243 | this.menuStrip1.Size = new System.Drawing.Size(704, 24); 244 | this.menuStrip1.TabIndex = 8; 245 | this.menuStrip1.Text = "menuStrip1"; 246 | // 247 | // fileToolStripMenuItem 248 | // 249 | this.fileToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { 250 | this.clearInfoToolStripMenuItem, 251 | this.exitToolStripMenuItem}); 252 | this.fileToolStripMenuItem.Name = "fileToolStripMenuItem"; 253 | this.fileToolStripMenuItem.Size = new System.Drawing.Size(37, 20); 254 | this.fileToolStripMenuItem.Text = "File"; 255 | // 256 | // clearInfoToolStripMenuItem 257 | // 258 | this.clearInfoToolStripMenuItem.Name = "clearInfoToolStripMenuItem"; 259 | this.clearInfoToolStripMenuItem.Size = new System.Drawing.Size(125, 22); 260 | this.clearInfoToolStripMenuItem.Text = "Clear Info"; 261 | this.clearInfoToolStripMenuItem.Click += new System.EventHandler(this.ClearInfoToolStripMenuItemClick); 262 | // 263 | // exitToolStripMenuItem 264 | // 265 | this.exitToolStripMenuItem.Name = "exitToolStripMenuItem"; 266 | this.exitToolStripMenuItem.Size = new System.Drawing.Size(125, 22); 267 | this.exitToolStripMenuItem.Text = "Exit"; 268 | this.exitToolStripMenuItem.Click += new System.EventHandler(this.ExitToolStripMenuItemClick); 269 | // 270 | // aboutToolStripMenuItem 271 | // 272 | this.aboutToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { 273 | this.aboutToolStripMenuItem1}); 274 | this.aboutToolStripMenuItem.Name = "aboutToolStripMenuItem"; 275 | this.aboutToolStripMenuItem.Size = new System.Drawing.Size(52, 20); 276 | this.aboutToolStripMenuItem.Text = "About"; 277 | // 278 | // aboutToolStripMenuItem1 279 | // 280 | this.aboutToolStripMenuItem1.Name = "aboutToolStripMenuItem1"; 281 | this.aboutToolStripMenuItem1.Size = new System.Drawing.Size(107, 22); 282 | this.aboutToolStripMenuItem1.Text = "About"; 283 | this.aboutToolStripMenuItem1.Click += new System.EventHandler(this.AboutToolStripMenuItem1Click); 284 | // 285 | // includeVersionInFolderBox 286 | // 287 | this.includeVersionInFolderBox.Anchor = System.Windows.Forms.AnchorStyles.Bottom; 288 | this.includeVersionInFolderBox.AutoSize = true; 289 | this.includeVersionInFolderBox.Location = new System.Drawing.Point(336, 387); 290 | this.includeVersionInFolderBox.Name = "includeVersionInFolderBox"; 291 | this.includeVersionInFolderBox.Size = new System.Drawing.Size(195, 17); 292 | this.includeVersionInFolderBox.TabIndex = 4; 293 | this.includeVersionInFolderBox.Text = "Append File Version to Folder Name"; 294 | this.includeVersionInFolderBox.UseVisualStyleBackColor = true; 295 | // 296 | // multiThreadCheckBox 297 | // 298 | this.multiThreadCheckBox.Anchor = System.Windows.Forms.AnchorStyles.Bottom; 299 | this.multiThreadCheckBox.AutoSize = true; 300 | this.multiThreadCheckBox.Location = new System.Drawing.Point(12, 416); 301 | this.multiThreadCheckBox.Name = "multiThreadCheckBox"; 302 | this.multiThreadCheckBox.Size = new System.Drawing.Size(151, 17); 303 | this.multiThreadCheckBox.TabIndex = 19; 304 | this.multiThreadCheckBox.Text = "Dump Files Simultaneously"; 305 | this.multiThreadCheckBox.UseVisualStyleBackColor = true; 306 | this.multiThreadCheckBox.CheckedChanged += new System.EventHandler(this.MultiThreadCheckBox_CheckedChanged); 307 | // 308 | // extractorThreadsNum 309 | // 310 | this.extractorThreadsNum.Anchor = System.Windows.Forms.AnchorStyles.Bottom; 311 | this.extractorThreadsNum.Enabled = false; 312 | this.extractorThreadsNum.Location = new System.Drawing.Point(246, 413); 313 | this.extractorThreadsNum.Minimum = new decimal(new int[] { 314 | 1, 315 | 0, 316 | 0, 317 | 0}); 318 | this.extractorThreadsNum.Name = "extractorThreadsNum"; 319 | this.extractorThreadsNum.Size = new System.Drawing.Size(39, 20); 320 | this.extractorThreadsNum.TabIndex = 25; 321 | this.extractorThreadsNum.Value = new decimal(new int[] { 322 | 1, 323 | 0, 324 | 0, 325 | 0}); 326 | // 327 | // extractorThreadsLabel 328 | // 329 | this.extractorThreadsLabel.Anchor = System.Windows.Forms.AnchorStyles.Bottom; 330 | this.extractorThreadsLabel.AutoSize = true; 331 | this.extractorThreadsLabel.Enabled = false; 332 | this.extractorThreadsLabel.Location = new System.Drawing.Point(168, 417); 333 | this.extractorThreadsLabel.Name = "extractorThreadsLabel"; 334 | this.extractorThreadsLabel.Size = new System.Drawing.Size(72, 13); 335 | this.extractorThreadsLabel.TabIndex = 20; 336 | this.extractorThreadsLabel.Text = "Max Threads:"; 337 | // 338 | // SelectWzFolder 339 | // 340 | this.SelectWzFolder.Anchor = System.Windows.Forms.AnchorStyles.Bottom; 341 | this.SelectWzFolder.Location = new System.Drawing.Point(610, 294); 342 | this.SelectWzFolder.Name = "SelectWzFolder"; 343 | this.SelectWzFolder.Size = new System.Drawing.Size(82, 23); 344 | this.SelectWzFolder.TabIndex = 21; 345 | this.SelectWzFolder.Text = "Select Folder"; 346 | this.SelectWzFolder.UseVisualStyleBackColor = true; 347 | this.SelectWzFolder.Click += new System.EventHandler(this.SelectWzFolder_Click); 348 | // 349 | // SelectExtractDestination 350 | // 351 | this.SelectExtractDestination.Anchor = System.Windows.Forms.AnchorStyles.Bottom; 352 | this.SelectExtractDestination.Location = new System.Drawing.Point(537, 324); 353 | this.SelectExtractDestination.Name = "SelectExtractDestination"; 354 | this.SelectExtractDestination.Size = new System.Drawing.Size(78, 23); 355 | this.SelectExtractDestination.TabIndex = 22; 356 | this.SelectExtractDestination.Text = "Select Folder"; 357 | this.SelectExtractDestination.UseVisualStyleBackColor = true; 358 | this.SelectExtractDestination.Click += new System.EventHandler(this.SelectExtractDestination_Click); 359 | // 360 | // LinkTypeLabel 361 | // 362 | this.LinkTypeLabel.Anchor = System.Windows.Forms.AnchorStyles.Bottom; 363 | this.LinkTypeLabel.AutoSize = true; 364 | this.LinkTypeLabel.Location = new System.Drawing.Point(168, 388); 365 | this.LinkTypeLabel.Name = "LinkTypeLabel"; 366 | this.LinkTypeLabel.Size = new System.Drawing.Size(57, 13); 367 | this.LinkTypeLabel.TabIndex = 23; 368 | this.LinkTypeLabel.Text = "Link Type:"; 369 | // 370 | // LinkTypeComboBox 371 | // 372 | this.LinkTypeComboBox.Anchor = System.Windows.Forms.AnchorStyles.Bottom; 373 | this.LinkTypeComboBox.Enabled = false; 374 | this.LinkTypeComboBox.FormattingEnabled = true; 375 | this.LinkTypeComboBox.Location = new System.Drawing.Point(231, 384); 376 | this.LinkTypeComboBox.Name = "LinkTypeComboBox"; 377 | this.LinkTypeComboBox.Size = new System.Drawing.Size(82, 21); 378 | this.LinkTypeComboBox.TabIndex = 24; 379 | this.LinkTypeComboBox.SelectedIndexChanged += new System.EventHandler(this.LinkTypeComboBox_SelectedIndexChanged); 380 | this.LinkTypeComboBox.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.LinkTypeComboBox_KeyPress); 381 | // 382 | // toolStripStatusLabel1 383 | // 384 | this.toolStripStatusLabel1.Name = "toolStripStatusLabel1"; 385 | this.toolStripStatusLabel1.Size = new System.Drawing.Size(0, 17); 386 | // 387 | // MainForm 388 | // 389 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 390 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 391 | this.ClientSize = new System.Drawing.Size(704, 461); 392 | this.Controls.Add(this.extractorThreadsNum); 393 | this.Controls.Add(this.extractorThreadsLabel); 394 | this.Controls.Add(this.LinkTypeComboBox); 395 | this.Controls.Add(this.multiThreadCheckBox); 396 | this.Controls.Add(this.LinkTypeLabel); 397 | this.Controls.Add(this.SelectExtractDestination); 398 | this.Controls.Add(this.SelectWzFolder); 399 | this.Controls.Add(this.includeVersionInFolderBox); 400 | this.Controls.Add(this.openFolderButton); 401 | this.Controls.Add(this.label5); 402 | this.Controls.Add(this.label4); 403 | this.Controls.Add(this.outputFolderTB); 404 | this.Controls.Add(this.WZFileTB); 405 | this.Controls.Add(this.label3); 406 | this.Controls.Add(this.MapleVersionComboBox); 407 | this.Controls.Add(this.label2); 408 | this.Controls.Add(this.versionBox); 409 | this.Controls.Add(this.CancelOpButton); 410 | this.Controls.Add(this.statusStrip1); 411 | this.Controls.Add(this.menuStrip1); 412 | this.Controls.Add(this.includePngMp3Box); 413 | this.Controls.Add(this.Info); 414 | this.Controls.Add(this.DumpWzButton); 415 | this.Controls.Add(this.SelectWzFileButton); 416 | this.MainMenuStrip = this.menuStrip1; 417 | this.MinimumSize = new System.Drawing.Size(720, 500); 418 | this.Name = "MainForm"; 419 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; 420 | this.Text = "WZ Dumper"; 421 | this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Form1FormClosing); 422 | this.Load += new System.EventHandler(this.Form1Load); 423 | this.statusStrip1.ResumeLayout(false); 424 | this.statusStrip1.PerformLayout(); 425 | this.menuStrip1.ResumeLayout(false); 426 | this.menuStrip1.PerformLayout(); 427 | ((System.ComponentModel.ISupportInitialize)(this.extractorThreadsNum)).EndInit(); 428 | this.ResumeLayout(false); 429 | this.PerformLayout(); 430 | 431 | } 432 | 433 | #endregion 434 | 435 | private System.Windows.Forms.Button SelectWzFileButton; 436 | private System.Windows.Forms.Button DumpWzButton; 437 | private System.Windows.Forms.TextBox Info; 438 | private System.Windows.Forms.CheckBox includePngMp3Box; 439 | private System.Windows.Forms.StatusStrip statusStrip1; 440 | private System.Windows.Forms.Button CancelOpButton; 441 | private SafeToolStripLabel toolStripStatusLabel1; 442 | private System.Windows.Forms.TextBox versionBox; 443 | private System.Windows.Forms.Label label2; 444 | private System.Windows.Forms.ComboBox MapleVersionComboBox; 445 | private System.Windows.Forms.Label label3; 446 | private System.Windows.Forms.TextBox WZFileTB; 447 | private System.Windows.Forms.TextBox outputFolderTB; 448 | private System.Windows.Forms.Label label4; 449 | private System.Windows.Forms.Label label5; 450 | private System.Windows.Forms.Button openFolderButton; 451 | private System.Windows.Forms.ToolStripMenuItem fileToolStripMenuItem; 452 | private System.Windows.Forms.ToolStripMenuItem exitToolStripMenuItem; 453 | private System.Windows.Forms.ToolStripMenuItem aboutToolStripMenuItem; 454 | private System.Windows.Forms.ToolStripMenuItem aboutToolStripMenuItem1; 455 | private System.Windows.Forms.MenuStrip menuStrip1; 456 | private System.Windows.Forms.CheckBox includeVersionInFolderBox; 457 | private System.Windows.Forms.ToolStripMenuItem clearInfoToolStripMenuItem; 458 | private System.Windows.Forms.CheckBox multiThreadCheckBox; 459 | private System.Windows.Forms.Label extractorThreadsLabel; 460 | private System.Windows.Forms.NumericUpDown extractorThreadsNum; 461 | private System.Windows.Forms.Button SelectWzFolder; 462 | private System.Windows.Forms.Button SelectExtractDestination; 463 | private System.Windows.Forms.Label LinkTypeLabel; 464 | private System.Windows.Forms.ComboBox LinkTypeComboBox; 465 | } 466 | } -------------------------------------------------------------------------------- /WZDumper/MainForm.cs: -------------------------------------------------------------------------------- 1 | using MapleLib.WzLib; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Diagnostics; 5 | using System.Globalization; 6 | using System.IO; 7 | using System.Linq; 8 | using System.Reflection; 9 | using System.Runtime.InteropServices; 10 | using System.Security.Principal; 11 | using System.Text.RegularExpressions; 12 | using System.Threading; 13 | using System.Threading.Tasks; 14 | using System.Windows.Forms; 15 | 16 | namespace WzDumper { 17 | public partial class MainForm : Form { 18 | [DllImport("kernel32.dll")] 19 | public static extern uint GetLastError(); 20 | [DllImport("Kernel32.dll", CharSet = CharSet.Unicode)] 21 | static extern bool CreateHardLink(string lpFileName, string lpExistingFileName, IntPtr lpSecurityAttributes); 22 | [DllImport("kernel32.dll", EntryPoint = "CreateSymbolicLinkW", CharSet = CharSet.Unicode, SetLastError = true)] 23 | static extern bool CreateSymbolicLink(string lpSymlinkFileName, string lpTargetFileName, int dwFlags); 24 | 25 | public MainForm() { 26 | InitializeComponent(); 27 | ToolTip toolTip = new ToolTip(); 28 | toolTip.SetToolTip(includePngMp3Box, "Extracts png and mp3 files along with the generated XML files"); 29 | string linkTypeText = "Sets the method for creating link files\n" + 30 | "Note: Symbolic and Hard links cannot be created when extracting to a remote drive.\n" + 31 | "Methods:\n" + 32 | "Symbolic (recommended, requires admin privilage, default when running as admin)\n" + 33 | "Hard (default when not running as admin, falls back to Copy mode for files that have reached the link limit)\n" + 34 | "Copy (creates another copy entirely, use this if extracting to a remote drive)"; 35 | toolTip.SetToolTip(LinkTypeLabel, linkTypeText); 36 | toolTip.SetToolTip(LinkTypeComboBox, linkTypeText); 37 | toolTip.SetToolTip(includeVersionInFolderBox, "Adds the file version to the end of the WZ folder (e.g. Base.wz_v81)"); 38 | toolTip.SetToolTip(multiThreadCheckBox, "This only applies when dumping from a folder.\nDumps multiple WZ files concurrently depending on the number of extractor threads."); 39 | toolTip.SetToolTip(extractorThreadsNum, "Sets the max number of WZ files you want to extract at once.\nDefault is the number of processor threads available."); 40 | toolTip.ReshowDelay = 500; 41 | toolTip.ShowAlways = true; 42 | extractorThreadsNum.Maximum = Environment.ProcessorCount; 43 | extractorThreadsNum.Value = Environment.ProcessorCount; 44 | } 45 | 46 | public bool IsError { get; set; } 47 | public bool IsFinished { get; set; } = true; 48 | public bool Exit { get; set; } 49 | public TextBox InfoTextBox { get { return Info; } } 50 | public CancellationTokenSource CancelSource { get; set; } 51 | public bool ShouldExtractMP3PNG => includePngMp3Box.Checked; 52 | public LinkType SelectedLinkType { get; set; } 53 | 54 | private bool IsElevated { 55 | get { 56 | bool isElevated; 57 | using (WindowsIdentity identity = WindowsIdentity.GetCurrent()) { 58 | WindowsPrincipal principal = new WindowsPrincipal(identity); 59 | isElevated = principal.IsInRole(WindowsBuiltInRole.Administrator); 60 | } 61 | return isElevated; 62 | } 63 | } 64 | 65 | private WzMapleVersion SelectedVersion { 66 | get { 67 | switch (MapleVersionComboBox.SelectedIndex) { 68 | case 1: 69 | return WzMapleVersion.GMS; 70 | case 2: 71 | return WzMapleVersion.EMS; 72 | default: 73 | return WzMapleVersion.CLASSIC; 74 | } 75 | } 76 | } 77 | 78 | private void SelectWzFile(object sender, EventArgs e) { 79 | var openFile = new OpenFileDialog { Title = "Select File", Filter = "WZ Files|*.wz|WZ Image Files|*.img" }; 80 | if (openFile.ShowDialog() == DialogResult.OK) { 81 | InputSelected(openFile.FileName); 82 | } 83 | openFile.Dispose(); 84 | } 85 | 86 | private void InputSelected(string input) { 87 | WZFileTB.Text = input; 88 | versionBox.Text = String.Empty; 89 | toolStripStatusLabel1.Text = String.Empty; 90 | DumpWzButton.Enabled = WZFileTB.Text.Length > 0 && outputFolderTB.Text.Length > 0; 91 | } 92 | 93 | public void UpdateToolstripStatus(string status) { 94 | toolStripStatusLabel1.Text = status; 95 | } 96 | 97 | private static void UpdateTextBox(TextBox tb, string info, bool append) { 98 | if (append) 99 | tb.AppendText(info); 100 | else 101 | tb.Text = info; 102 | } 103 | 104 | private void DumpListWz(WzListFile file, string fName, string directory, DateTime startTime) { 105 | var error = false; 106 | TextWriter tw = new StreamWriter(directory + "\\List.txt"); 107 | try { 108 | foreach (var listEntry in file.WzListEntries) { 109 | tw.WriteLine(listEntry); 110 | } 111 | } catch (Exception e) { 112 | error = true; 113 | MessageBox.Show("An error occurred: " + e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); 114 | if (Directory.GetFiles(directory).Length == 0) 115 | Directory.Delete(directory, true); 116 | } finally { 117 | tw.Dispose(); 118 | } 119 | if (error) { 120 | UpdateTextBoxInfo(Info, "An error occurred while dumping " + fName, true); 121 | UpdateToolstripStatus("An error occurred while dumping " + fName); 122 | } else { 123 | var duration = DateTime.Now - startTime; 124 | UpdateTextBoxInfo(Info, "Finished dumping " + fName + " in " + GetDurationAsString(duration), true); 125 | UpdateToolstripStatus("Dumped " + fName + " successfully"); 126 | } 127 | } 128 | 129 | private static string GetValidFolderName(string baseFolder, bool checkFileOnly) { 130 | var currFolder = baseFolder; 131 | var index = 1; 132 | if (checkFileOnly) { 133 | while (File.Exists(currFolder)) { 134 | currFolder = baseFolder + "-" + index; 135 | index++; 136 | } 137 | } else { 138 | while (Directory.Exists(currFolder) || File.Exists(currFolder)) { 139 | currFolder = baseFolder + "-" + index; 140 | index++; 141 | } 142 | } 143 | return currFolder; 144 | } 145 | 146 | private void DumpFile(object sender, EventArgs e) { 147 | CheckOutputPath(); 148 | UpdateToolstripStatus("Parsing..."); 149 | DisableButtons(); 150 | var filePath = WZFileTB.Text; 151 | FileAttributes attr = File.GetAttributes(filePath); 152 | if (!attr.HasFlag(FileAttributes.Directory)) { 153 | var ext = Path.GetExtension(filePath); 154 | if (ext != null && String.Compare(ext, ".img", StringComparison.OrdinalIgnoreCase) == 0) { 155 | DumpXmlFromWzImage(filePath); 156 | return; 157 | } 158 | WzListFile listFile = null; 159 | WzFile regFile = null; 160 | try { 161 | if (filePath.EndsWith("List.wz", StringComparison.CurrentCultureIgnoreCase)) { 162 | listFile = new WzListFile(filePath, SelectedVersion); 163 | listFile.ParseWzFile(); 164 | } else { 165 | List s = new List(); 166 | regFile = new WzFile(filePath, SelectedVersion, s); 167 | regFile.ParseWzFile(); 168 | } 169 | } catch (UnauthorizedAccessException) { 170 | regFile?.Dispose(); 171 | MessageBox.Show("Please re-run this program as an administrator.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Stop); 172 | UpdateToolstripStatus(""); 173 | EnableButtons(); 174 | return; 175 | } catch (Exception ex) { 176 | regFile?.Dispose(); 177 | MessageBox.Show("An error occurred while parsing this file: " + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); 178 | Info.AppendText(ex.StackTrace); 179 | UpdateToolstripStatus(""); 180 | EnableButtons(); 181 | return; 182 | } 183 | if (listFile == null) 184 | versionBox.Text = regFile.Version.ToString(CultureInfo.CurrentCulture); 185 | var fileName = Path.GetFileName(filePath); 186 | var extractDir = outputFolderTB.Text; 187 | var extractFolder = Path.Combine(extractDir, fileName); 188 | if (listFile == null && includeVersionInFolderBox.Checked) 189 | extractFolder += "_v" + regFile.Version; 190 | if (File.Exists(extractFolder)) { 191 | extractFolder = GetValidFolderName(extractFolder, true); 192 | } 193 | if (Directory.Exists(extractFolder)) { 194 | var result = MessageBox.Show(extractFolder + " already exists.\r\nDo you want to overwrite that folder?\r\nNote: Clicking No will make a new folder.", "Folder Already Exists", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Warning); 195 | if (result == DialogResult.Cancel) { 196 | regFile?.Dispose(); 197 | UpdateToolstripStatus(""); 198 | EnableButtons(); 199 | return; 200 | } 201 | if (result != DialogResult.Yes) { 202 | extractFolder = GetValidFolderName(extractFolder, false); 203 | } 204 | } 205 | if (!Directory.Exists(extractFolder)) 206 | Directory.CreateDirectory(extractFolder); 207 | if (listFile != null) { 208 | Info.AppendText("Dumping data from " + fileName + " to " + extractFolder + "...\r\n"); 209 | } else if (includePngMp3Box.Checked) { 210 | Info.AppendText("Dumping MP3s, PNGs and XMLs from " + fileName + " to " + extractFolder + "...\r\n"); 211 | } else { 212 | Info.AppendText("Dumping XMLs from " + fileName + " to " + extractFolder + "...\r\n"); 213 | } 214 | if (listFile != null) { 215 | DumpListWz(listFile, fileName, extractFolder, DateTime.Now); 216 | listFile.Dispose(); 217 | EnableButtons(); 218 | } else { 219 | UpdateToolstripStatus("Preparing..."); 220 | CancelSource = new CancellationTokenSource(); 221 | CreateSingleDumperThread(regFile, new WzXml(this, extractDir, new DirectoryInfo(extractFolder).Name, includePngMp3Box.Checked, SelectedLinkType), fileName); 222 | } 223 | } else { 224 | string filesFound = "WZ Files Found: "; 225 | var allFiles = Directory.GetFiles(filePath, "*.wz"); 226 | var nextLevelFiles = GetWzFilesInFolder(filePath); 227 | if (allFiles.Length != 0 || nextLevelFiles.Count != 0) { 228 | if (allFiles.Length == 0) 229 | allFiles = nextLevelFiles.ToArray(); 230 | allFiles = allFiles.Where(fileName => !Regex.IsMatch(fileName, "[0-9]{3}.wz$", RegexOptions.IgnoreCase)).ToArray(); 231 | foreach (var fileName in allFiles) { 232 | filesFound += Path.GetFileName(fileName) + ", "; 233 | } 234 | Info.AppendText(filesFound.Substring(0, filesFound.Length - 2) + "\r\n"); 235 | if (allFiles.Length == 0) { 236 | Array.Sort(allFiles, FileSizeCompare); 237 | } else { 238 | SortedDictionary fileOrder = new SortedDictionary(); 239 | foreach (var fileName in allFiles) { 240 | FileInfo wzFile = new FileInfo(fileName); 241 | fileOrder.Add(DirSize(wzFile.Directory), fileName); 242 | } 243 | allFiles = fileOrder.Values.ToArray(); 244 | } 245 | CreateMultipleDumperThreads(filePath, allFiles, outputFolderTB.Text); 246 | } else { 247 | MessageBox.Show("There are no WZ Files located in the selected folder. Please choose a different folder.", "No WZ Files Found", MessageBoxButtons.OK, MessageBoxIcon.Error); 248 | UpdateToolstripStatus(""); 249 | EnableButtons(); 250 | } 251 | } 252 | } 253 | 254 | private static long DirSize(DirectoryInfo dirInfo) { 255 | long size = 0; 256 | FileInfo[] fis = dirInfo.GetFiles(); 257 | foreach (FileInfo fi in fis) { 258 | size += fi.Length; 259 | } 260 | DirectoryInfo[] dis = dirInfo.GetDirectories(); 261 | foreach (DirectoryInfo di in dis) { 262 | size += DirSize(di); 263 | } 264 | return size; 265 | } 266 | 267 | private void DumpXmlFromWzImage(string path) { 268 | var fName = Path.GetFileName(path); 269 | if (fName == null) 270 | return; 271 | FileStream fStream; 272 | WzImage img; 273 | try { 274 | fStream = File.Open(path, FileMode.Open); 275 | img = new WzImage(fName, fStream, SelectedVersion); 276 | img.ParseImage(); 277 | } catch (IOException ex) { 278 | MessageBox.Show("Unable to read file: " + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); 279 | return; 280 | } catch (ArgumentException) { 281 | MessageBox.Show("Please select a WZ Image File.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); 282 | return; 283 | } catch (UnauthorizedAccessException) { 284 | MessageBox.Show("Please re-run this program as an administrator to be able to dump files that are not in the OS drive.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Stop); 285 | return; 286 | } catch (Exception) { 287 | MessageBox.Show("Please select a valid WZ Image File.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); 288 | return; 289 | } 290 | if (img.WzProperties.Count() == 0) { 291 | img.Dispose(); 292 | fStream.Dispose(); 293 | MessageBox.Show("This image file contained no data when parsing. Please select a different Maple Version.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); 294 | return; 295 | } 296 | var open = new FolderBrowserDialog(); 297 | if (open.ShowDialog() != DialogResult.OK) { 298 | img.Dispose(); 299 | open.Dispose(); 300 | return; 301 | } 302 | var extractFolder = Path.Combine(open.SelectedPath, fName); 303 | if (File.Exists(extractFolder)) { 304 | extractFolder = GetValidFolderName(extractFolder, true); 305 | } 306 | if (Directory.Exists(extractFolder)) { 307 | var result = MessageBox.Show(extractFolder + " already exists.\r\nDo you want to overwrite that folder?\r\nNote: Clicking No will make a new folder.", "Folder Already Exists", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Warning); 308 | if (result == DialogResult.Cancel) 309 | return; 310 | if (result != DialogResult.Yes) { 311 | extractFolder = GetValidFolderName(Path.Combine(open.SelectedPath, fName), false); 312 | } 313 | } 314 | 315 | if (!Directory.Exists(extractFolder)) 316 | Directory.CreateDirectory(extractFolder); 317 | DisableButtons(); 318 | Info.AppendText("Dumping data from " + fName + " to " + extractFolder + "...\r\n"); 319 | var startTime = DateTime.Now; 320 | CancelSource = new CancellationTokenSource(); 321 | string startingPath = new DirectoryInfo(extractFolder).Name; 322 | new WzXml(this, open.SelectedPath, startingPath, includePngMp3Box.Checked, SelectedLinkType).DumpImage(img, startingPath); 323 | open.Dispose(); 324 | img.Dispose(); 325 | fStream.Dispose(); 326 | CancelSource.Dispose(); 327 | var duration = DateTime.Now - startTime; 328 | UpdateTextBoxInfo(Info, "Finished dumping " + fName + " in " + GetDurationAsString(duration), true); 329 | UpdateToolstripStatus("Dumped " + fName + " successfully"); 330 | EnableButtons(); 331 | } 332 | 333 | private void CreateSingleDumperThread(WzFile file, WzXml wzxml, string fileName) { 334 | IsFinished = false; 335 | var startTime = DateTime.Now; 336 | var mainTask = Task.Factory.StartNew(() => DirectoryDumperThread(file, wzxml, true)); 337 | mainTask.ContinueWith(p => { 338 | var duration = DateTime.Now - startTime; 339 | string message = String.Empty; 340 | if (CancelSource.Token.IsCancellationRequested) { 341 | if (Exit) 342 | return; 343 | message = "Canceled dumping " + fileName; 344 | } else if (IsError) { 345 | message = "An error occurred while dumping " + fileName; 346 | } else { 347 | message = "Finished dumping " + fileName; 348 | } 349 | UpdateToolstripStatus(message); 350 | UpdateTextBoxInfo(Info, message + ".\r\nElapsed time: " + GetDurationAsString(duration), true); 351 | IsError = false; 352 | IsFinished = true; 353 | EnableButtons(); 354 | CancelSource.Dispose(); 355 | }, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.FromCurrentSynchronizationContext()); 356 | } 357 | 358 | private void InitThread(string fileName, string dumpFolder, WzMapleVersion selectedValue) { 359 | WzListFile listFile = null; 360 | WzFile regFile = null; 361 | var message = String.Empty; 362 | try { 363 | if (fileName.EndsWith("List.wz", StringComparison.CurrentCultureIgnoreCase)) { 364 | listFile = new WzListFile(fileName, selectedValue); 365 | listFile.ParseWzFile(); 366 | } else { 367 | List s = new List(); 368 | regFile = new WzFile(fileName, selectedValue, s); 369 | regFile.ParseWzFile(); 370 | } 371 | } catch (IOException ex) { 372 | regFile?.Dispose(); 373 | message = "An IO error occurred: " + ex.Message; 374 | } catch (UnauthorizedAccessException) { 375 | regFile?.Dispose(); 376 | message = "Please re-run this program as an administrator."; 377 | } catch (Exception ex) { 378 | regFile?.Dispose(); 379 | message = "An error occurred while parsing this file: " + ex.Message; 380 | } 381 | if (!String.IsNullOrEmpty(message)) { 382 | UpdateTextBoxInfo(Info, "Error while parsing file " + Path.GetFileName(fileName) + "\r\nMessage: " + message + "\r\nContinuing...", true); 383 | if (!fileName.EndsWith("List.wz")) 384 | IsError = true; 385 | return; 386 | } 387 | if (regFile == null && listFile == null) 388 | return; 389 | var wzName = Path.GetFileName(fileName); 390 | var nFolder = Path.Combine(dumpFolder, wzName); 391 | if (listFile == null && includeVersionInFolderBox.Checked) 392 | nFolder += "_v" + regFile.Version; 393 | nFolder = GetValidFolderName(nFolder, false); 394 | if (!Directory.Exists(nFolder)) 395 | Directory.CreateDirectory(nFolder); 396 | if (listFile == null) 397 | UpdateTextBoxInfo(versionBox, regFile.Version.ToString(CultureInfo.CurrentCulture), false); 398 | if (listFile != null) { 399 | UpdateTextBoxInfo(Info, "Dumping data from " + wzName + " to " + nFolder + "...", true); 400 | } else if (includePngMp3Box.Checked) { 401 | UpdateTextBoxInfo(Info, "Dumping MP3s, PNGs and XMLs from " + wzName + " to " + nFolder + "...", true); 402 | } else { 403 | UpdateTextBoxInfo(Info, "Dumping XMLs from " + wzName + " to " + nFolder + "...", true); 404 | } 405 | if (listFile != null) { 406 | DumpListWz(listFile, wzName, nFolder, DateTime.Now); 407 | listFile.Dispose(); 408 | } else { 409 | DirectoryDumperThread(regFile, new WzXml(this, dumpFolder, new DirectoryInfo(nFolder).Name, includePngMp3Box.Checked, SelectedLinkType)); 410 | } 411 | } 412 | 413 | private void CreateMultipleDumperThreads(string wzFolder, IEnumerable files, string dumpFolder) { 414 | IsFinished = false; 415 | var startTime = DateTime.Now; 416 | CancelSource = new CancellationTokenSource(); 417 | var version = SelectedVersion; 418 | var t = Task.Factory.StartNew(() => { 419 | var pOps = new ParallelOptions { MaxDegreeOfParallelism = multiThreadCheckBox.Checked ? Math.Min(((string[])files).Length, (int)extractorThreadsNum.Value) : 1 }; 420 | Parallel.ForEach(files, pOps, file => { 421 | if (CancelSource.Token.IsCancellationRequested) 422 | return; 423 | InitThread(file, dumpFolder, version); 424 | }); 425 | }); 426 | t.ContinueWith(p => { 427 | var duration = DateTime.Now - startTime; 428 | if (CancelSource.Token.IsCancellationRequested) { 429 | if (Exit) 430 | return; 431 | UpdateTextBoxInfo(Info, "Canceled dumping WZ Files. Elapsed time: " + GetDurationAsString(duration), true); 432 | UpdateToolstripStatus("Dumping WZ Files canceled"); 433 | } else if (IsError) { 434 | UpdateTextBoxInfo(Info, "An error occurred while dumping WZ Files. Elapsed time: " + GetDurationAsString(duration), true); 435 | UpdateToolstripStatus("An error occurred while dumping WZ Files"); 436 | } else { 437 | UpdateTextBoxInfo(Info, "Finished dumping all WZ Files in " + wzFolder + " in " + GetDurationAsString(duration), true); 438 | UpdateToolstripStatus("Dumped all WZ Files successfully"); 439 | } 440 | IsError = false; 441 | IsFinished = true; 442 | EnableButtons(); 443 | CancelSource.Dispose(); 444 | }, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.FromCurrentSynchronizationContext()); 445 | } 446 | 447 | private void DirectoryDumperThread(WzDirectory dir, WzXml wzxml, bool singleDump = false) { 448 | if (CancelSource.Token.IsCancellationRequested) 449 | return; 450 | try { 451 | wzxml.DumpDir(dir); 452 | if (!singleDump && !CancelSource.Token.IsCancellationRequested) 453 | UpdateTextBoxInfo(Info, "Finished dumping " + dir.Name, true); 454 | } catch (Exception ex) { 455 | if (!CancelSource.Token.IsCancellationRequested) { 456 | UpdateTextBoxInfo(Info, dir.Name + " Exception: " + ex.Message + " " + ex.StackTrace, true); 457 | IsError = true; 458 | } 459 | } finally { 460 | dir.Dispose(); 461 | } 462 | } 463 | 464 | private static string GetDurationAsString(TimeSpan duration) { 465 | string s = String.Empty; 466 | if (duration.Hours != 0) { 467 | s += duration.Hours + " hour"; 468 | if (duration.Hours != 1) 469 | s += "s"; 470 | } 471 | if (duration.Minutes != 0) { 472 | if (!string.IsNullOrEmpty(s)) 473 | s += ", "; 474 | s += duration.Minutes + " minute"; 475 | if (duration.Minutes != 1) 476 | s += "s"; 477 | s += ", "; 478 | } 479 | s += duration.Seconds + " second"; 480 | if (duration.Seconds != 1) 481 | s += "s"; 482 | s += " and "; 483 | s += duration.Milliseconds + " millisecond"; 484 | if (duration.Milliseconds != 1) 485 | s += "s"; 486 | return s; 487 | } 488 | 489 | private void CancelOperation(object sender, EventArgs e) { 490 | if (MessageBox.Show("Are you sure you want to cancel the current operation?", "Cancel", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) != DialogResult.Yes) 491 | return; 492 | CancelSource?.Cancel(true); 493 | CancelOpButton.Enabled = false; 494 | UpdateTextBoxInfo(Info, "Canceling... Waiting for the current image(s) to finish dumping...", true); 495 | } 496 | 497 | private void Form1Load(object sender, EventArgs e) { 498 | if (!File.Exists(Application.StartupPath + @"\MapleLib.dll")) { 499 | MessageBox.Show("Please make sure MapleLib.dll is in the program directory before executing the program.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Stop); 500 | Close(); 501 | return; 502 | } 503 | var args = Environment.GetCommandLineArgs(); 504 | for (int i = 1; i < args.Length; i++) { 505 | string arg = args[i]; 506 | if (arg.Equals("-a")) { 507 | includePngMp3Box.Checked = true; 508 | } else if (arg.Equals("-o")) { 509 | if (i + 1 < args.Length) { 510 | string output = args[++i]; 511 | if (Directory.Exists(output)) 512 | outputFolderTB.Text = output; 513 | } 514 | } else { 515 | if (!arg.Equals("") && (arg.Contains("wz") || Directory.Exists(arg))) { 516 | InputSelected(arg); 517 | } 518 | } 519 | } 520 | MapleVersionComboBox.SelectedIndex = 0; 521 | LinkTypeComboBox.DataSource = Enum.GetValues(typeof(LinkType)); 522 | LinkTypeComboBox.SelectedItem = IsElevated ? LinkType.Symbolic : LinkType.Hard; 523 | } 524 | 525 | private void Form1FormClosing(object sender, FormClosingEventArgs e) { 526 | if (IsFinished) 527 | return; 528 | if (MessageBox.Show("You can not close the program while it is still dumping. Do you wish to cancel the operation?", "Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes) { 529 | Exit = true; 530 | CancelSource?.Cancel(true); 531 | } else { 532 | e.Cancel = true; 533 | } 534 | } 535 | 536 | private void ClearInfoToolStripMenuItemClick(object sender, EventArgs e) { 537 | Info.Text = String.Empty; 538 | toolStripStatusLabel1.Text = String.Empty; 539 | } 540 | 541 | private void OpenFolder(object sender, EventArgs e) { 542 | Process.Start("explorer.exe", outputFolderTB.Text); 543 | } 544 | 545 | private void ExitToolStripMenuItemClick(object sender, EventArgs e) { 546 | Close(); 547 | } 548 | 549 | private static Form IsFormAlreadyOpen(Type formType) { 550 | return Application.OpenForms.Cast
().FirstOrDefault(openForm => openForm.GetType() == formType); 551 | } 552 | 553 | private void AboutToolStripMenuItem1Click(object sender, EventArgs e) { 554 | Form taskFormName; 555 | if ((taskFormName = IsFormAlreadyOpen(typeof(About))) == null) { 556 | taskFormName = new About(); 557 | taskFormName.Show(); 558 | } else { 559 | taskFormName.WindowState = FormWindowState.Normal; 560 | taskFormName.BringToFront(); 561 | } 562 | } 563 | 564 | private void EnableButtons() { 565 | SelectWzFileButton.Enabled = true; 566 | SelectWzFolder.Enabled = true; 567 | SelectExtractDestination.Enabled = true; 568 | LinkTypeComboBox.Enabled = includePngMp3Box.Checked; 569 | DumpWzButton.Enabled = true; 570 | CancelOpButton.Enabled = false; 571 | includePngMp3Box.Enabled = true; 572 | includeVersionInFolderBox.Enabled = true; 573 | MapleVersionComboBox.Enabled = true; 574 | multiThreadCheckBox.Enabled = true; 575 | if (!string.IsNullOrEmpty(outputFolderTB.Text)) 576 | openFolderButton.Focus(); 577 | else 578 | SelectWzFileButton.Focus(); 579 | extractorThreadsLabel.Enabled = multiThreadCheckBox.Checked; 580 | extractorThreadsNum.Enabled = multiThreadCheckBox.Checked; 581 | } 582 | 583 | private void DisableButtons() { 584 | SelectWzFileButton.Enabled = false; 585 | SelectWzFolder.Enabled = false; 586 | SelectExtractDestination.Enabled = false; 587 | LinkTypeComboBox.Enabled = false; 588 | DumpWzButton.Enabled = false; 589 | CancelOpButton.Enabled = true; 590 | includePngMp3Box.Enabled = false; 591 | includeVersionInFolderBox.Enabled = false; 592 | MapleVersionComboBox.Enabled = false; 593 | multiThreadCheckBox.Enabled = false; 594 | extractorThreadsLabel.Enabled = false; 595 | extractorThreadsNum.Enabled = false; 596 | Info.Focus(); 597 | } 598 | 599 | private static int FileSizeCompare(string x, string y) { 600 | var file1 = new FileInfo(x); 601 | var file2 = new FileInfo(y); 602 | return Convert.ToInt32(file1.Length - file2.Length); 603 | } 604 | 605 | public void UpdateTextBoxInfo(TextBox tb, string info, bool appendNewLine) { 606 | if (appendNewLine) 607 | info += "\r\n"; 608 | if (tb.InvokeRequired && tb.IsHandleCreated) { 609 | Invoke(new UpdateTextBoxDelegate(UpdateTextBox), new object[] { tb, info, appendNewLine }); 610 | } else { 611 | UpdateTextBox(tb, info, appendNewLine); 612 | } 613 | } 614 | 615 | private void MapleVersionComboBoxKeyPress(object sender, KeyPressEventArgs e) { 616 | e.Handled = true; 617 | } 618 | 619 | #region Nested type: UpdateTextBoxDelegate 620 | 621 | private delegate void UpdateTextBoxDelegate(TextBox tb, string info, bool append); 622 | 623 | #endregion 624 | 625 | private void MultiThreadCheckBox_CheckedChanged(object sender, EventArgs e) { 626 | extractorThreadsLabel.Enabled = multiThreadCheckBox.Checked; 627 | extractorThreadsNum.Enabled = multiThreadCheckBox.Checked; 628 | } 629 | 630 | private void CheckOutputPath() { 631 | if (outputFolderTB.Text.Length != 0) { 632 | if (includePngMp3Box.Checked && !LinkTypeComboBox.SelectedItem.Equals(LinkType.Copy)) { 633 | String testFile = Path.Combine(outputFolderTB.Text, "test", "file"); 634 | String testFile2 = Path.Combine(outputFolderTB.Text, "test", "link"); 635 | FileInfo fi = new FileInfo(testFile); 636 | fi.Directory.Create(); 637 | fi.Create().Close(); 638 | bool res = LinkTypeComboBox.SelectedItem.Equals(LinkType.Symbolic) ? CreateSymbolicLink(testFile2, testFile, 0) : CreateHardLink(testFile2, testFile, IntPtr.Zero); 639 | if (!res) { 640 | MessageBox.Show("A test link could not be created on the output drive. The Link Type will be changed to Copy.", "Unable to Create Test Link", MessageBoxButtons.OK, MessageBoxIcon.Warning); 641 | LinkTypeComboBox.SelectedItem = LinkType.Copy; 642 | } 643 | fi.Directory.Delete(true); 644 | } 645 | } 646 | } 647 | 648 | private void IncludePngMp3Box_CheckedChanged(object sender, EventArgs e) { 649 | LinkTypeComboBox.Enabled = includePngMp3Box.Checked; 650 | CheckOutputPath(); 651 | } 652 | 653 | public List GetWzFilesInFolder(String path) { 654 | List wzFiles = new List(); 655 | string[] dirs = Directory.GetDirectories(path); 656 | foreach (var dir in dirs) { 657 | wzFiles.AddRange(Directory.GetFiles(dir, "*.wz")); 658 | } 659 | return wzFiles; 660 | } 661 | 662 | private void SelectWzFolder_Click(object sender, EventArgs e) { 663 | var open = new FolderBrowserDialog { Description = "Select the folder that contains the WZ Files you wish to dump" }; 664 | if (open.ShowDialog() == DialogResult.OK) { 665 | var allFiles = Directory.GetFiles(open.SelectedPath, "*.wz"); 666 | if (allFiles.Length == 0 && GetWzFilesInFolder(open.SelectedPath).Count == 0) { 667 | MessageBox.Show("There are no WZ Files located in the selected folder. Please choose a different folder.", "No WZ Files Found", MessageBoxButtons.OK, MessageBoxIcon.Error); 668 | } else { 669 | InputSelected(open.SelectedPath); 670 | } 671 | } 672 | open.Dispose(); 673 | } 674 | 675 | private void SelectExtractDestination_Click(object sender, EventArgs e) { 676 | var open = new FolderBrowserDialog { Description = "Select the folder you wish to dump to" }; 677 | if (open.ShowDialog() == DialogResult.OK) { 678 | outputFolderTB.Text = open.SelectedPath; 679 | DumpWzButton.Enabled = WZFileTB.Text.Length > 0 && outputFolderTB.Text.Length > 0; 680 | openFolderButton.Enabled = true; 681 | CheckOutputPath(); 682 | } 683 | open.Dispose(); 684 | 685 | } 686 | 687 | private void LinkTypeComboBox_SelectedIndexChanged(object sender, EventArgs e) { 688 | if (LinkTypeComboBox.SelectedItem.Equals(LinkType.Symbolic) && !IsElevated) { 689 | var result = MessageBox.Show("Creating symbolic links require administrative permission. Do you want to restart this program as an administrator?", "Admin Privileges Required", MessageBoxButtons.YesNo, MessageBoxIcon.Warning); 690 | if (result == DialogResult.Yes) { 691 | try { 692 | ProcessStartInfo processInfo = new ProcessStartInfo { 693 | Verb = "runas", 694 | FileName = Assembly.GetExecutingAssembly().Location, 695 | UseShellExecute = true, 696 | Arguments = "\"" + WZFileTB.Text + "\" -o \"" + outputFolderTB.Text + "\"" + (includePngMp3Box.Checked ? " -a" : "") 697 | }; 698 | Process.Start(processInfo); 699 | Close(); 700 | } catch (Exception) { } 701 | } else { 702 | LinkTypeComboBox.SelectedItem = SelectedLinkType; 703 | } 704 | } 705 | SelectedLinkType = (LinkType)LinkTypeComboBox.SelectedItem; 706 | } 707 | 708 | private void LinkTypeComboBox_KeyPress(object sender, KeyPressEventArgs e) { 709 | e.Handled = true; 710 | } 711 | } 712 | 713 | public enum LinkType : int { 714 | Hard = 1, 715 | Symbolic = 2, 716 | Copy = 3 717 | } 718 | } --------------------------------------------------------------------------------