├── .gitattributes ├── .gitignore ├── AdvancedDataGridView ├── AdvancedDataGridView.cs ├── AdvancedDataGridView.csproj ├── ChangeTracking.cs ├── ColumnHeader.cs ├── ColumnMenu.cs ├── ColumnMenu.designer.cs ├── DataCache.cs ├── FilterForm.Designer.cs ├── FilterForm.cs ├── FilterForm.resx ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ └── Resources.resx └── Resources │ └── Images │ ├── ColumnHeader_Filtered.png │ ├── ColumnHeader_FilteredAndOrderedASC.png │ ├── ColumnHeader_FilteredAndOrderedDESC.png │ ├── ColumnHeader_OrderedASC.png │ ├── ColumnHeader_OrderedDESC.png │ ├── ColumnHeader_UnFiltered.png │ ├── MenuStrip_OrderASCtxt.png │ ├── MenuStrip_OrderDESCtxt.png │ └── MenuStrip_ResizeGrip.png ├── CHANGES.md ├── Help ├── CommandLine.htm ├── DataGrid.htm ├── FindReplace.htm ├── Help.chm ├── Help.hhp ├── Images │ ├── DataGrid.png │ ├── Definition Editor.png │ ├── Definition Selector.png │ ├── FindReplace.png │ └── SQL Import.png ├── Import_Export.htm ├── Introduction.htm ├── Main Screen │ ├── btn_next_n.gif │ └── btn_prev_n.gif ├── Menu_Items.htm ├── Notes.htm ├── Tools.htm ├── help.hhc └── help.hhk ├── README.md ├── Run on Linux.md ├── UpdateDBC.bat ├── WDBXEditor.sln ├── WDBXEditor ├── About.Designer.cs ├── About.cs ├── About.resx ├── App.config ├── Archives │ ├── CASC │ │ ├── Constants │ │ │ └── Locales.cs │ │ ├── Handlers │ │ │ ├── BuildConfig.cs │ │ │ ├── BuildInfo.cs │ │ │ ├── CASCHandler.cs │ │ │ ├── CDNConfig.cs │ │ │ ├── DataFile.cs │ │ │ ├── EncodingFile.cs │ │ │ ├── IndexFile.cs │ │ │ └── RootFile.cs │ │ ├── Misc │ │ │ ├── ByteArrayComparer.cs │ │ │ ├── Extensions.cs │ │ │ └── Lookup3.cs │ │ └── Structures │ │ │ ├── BLTEChunk.cs │ │ │ ├── BLTEEntry.cs │ │ │ ├── EncodingEntry.cs │ │ │ ├── IndexEntry.cs │ │ │ └── RootEntry.cs │ └── MPQ │ │ ├── MpqArchive.cs │ │ ├── MpqArchiveCompactingEventArgs.cs │ │ ├── MpqFileStream.cs │ │ └── Native │ │ ├── Callbacks.cs │ │ ├── MpqArchiveSafeHandle.cs │ │ ├── MpqFileSafeHandle.cs │ │ ├── NativeMethods.cs │ │ ├── SFileInfoClass.cs │ │ ├── SFileOpenArchiveFlags.cs │ │ └── Win32Methods.cs ├── Common │ ├── AutoProgressBar.cs │ ├── BufferedListBox.cs │ ├── ColourWheel.cs │ ├── Constants.cs │ ├── DropdownCheckList.Designer.cs │ ├── DropdownCheckList.cs │ ├── DropdownCheckList.resx │ ├── Extensions.cs │ ├── FloatUtil.cs │ ├── FormHandler.cs │ ├── GithubReleaseModel.cs │ └── ORowComparer.cs ├── ConsoleHandler │ ├── ConsoleCommands.cs │ └── ConsoleManager.cs ├── Definitions │ ├── Alpha 0.5.3 (3368).xml │ ├── BfA 8.0.1 (26231).xml │ ├── BfA 8.0.1 (26367).xml │ ├── BfA 8.0.1 (26806).xml │ ├── BfA 8.0.1 (27075).xml │ ├── BfA 8.2.5 (32978).xml │ ├── Cata 4.3.4 (15595).xml │ ├── Classic 1.12.1 (5875).xml │ ├── Legion 7.0.3 (22248).xml │ ├── Legion 7.1.0 (22578).xml │ ├── Legion 7.2.0 (23835).xml │ ├── Legion 7.3.0 (24492).xml │ ├── Legion 7.3.0 (24793).xml │ ├── Legion 7.3.5 (25632).xml │ ├── Legion 7.3.5 (26654).xml │ ├── Legion 7.3.5 (26972).xml │ ├── MoP 5.4.8 (18414).xml │ ├── Offsets.json │ ├── TBC 2.4.3 (8606).xml │ ├── WDB.xml │ ├── WoD 6.2.4 (21742).xml │ └── WotLK 3.3.5 (12340).xml ├── EditDefinition.Designer.cs ├── EditDefinition.cs ├── EditDefinition.resx ├── Forms │ ├── ColourConverter.Designer.cs │ ├── ColourConverter.cs │ ├── ColourConverter.resx │ ├── ErrorReport.Designer.cs │ ├── ErrorReport.cs │ ├── ErrorReport.resx │ ├── FindReplace.Designer.cs │ ├── FindReplace.cs │ ├── FindReplace.resx │ ├── InputBox.cs │ ├── LegionParser.Designer.cs │ ├── LegionParser.cs │ ├── LegionParser.resx │ ├── LoadCSV.Designer.cs │ ├── LoadCSV.cs │ ├── LoadCSV.resx │ ├── LoadDefinition.Designer.cs │ ├── LoadDefinition.cs │ ├── LoadDefinition.resx │ ├── LoadHotfix.Designer.cs │ ├── LoadHotfix.cs │ ├── LoadHotfix.resx │ ├── LoadMPQ.Designer.cs │ ├── LoadMPQ.cs │ ├── LoadMPQ.resx │ ├── LoadSQL.Designer.cs │ ├── LoadSQL.cs │ ├── LoadSQL.resx │ ├── PlayerLocation.Designer.cs │ ├── PlayerLocation.cs │ ├── PlayerLocation.resx │ ├── TextEditor.Designer.cs │ ├── TextEditor.cs │ ├── TextEditor.resx │ ├── WotLKItemFix.Designer.cs │ ├── WotLKItemFix.cs │ └── WotLKItemFix.resx ├── Help.chm ├── InstanceManager.cs ├── Main.Designer.cs ├── Main.cs ├── Main.resx ├── NamedPipeManager.cs ├── Program.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Settings.Designer.cs │ └── Settings.settings ├── Reader │ ├── BitStream.cs │ ├── ColumnStructureEntry.cs │ ├── DBHeader.cs │ ├── DBReader.cs │ ├── DBReaderExtensions.cs │ ├── FieldStructureEntry.cs │ ├── FileTypes │ │ ├── HTFX.cs │ │ ├── WCH5.cs │ │ ├── WCH7.cs │ │ ├── WCH8.cs │ │ ├── WDB.cs │ │ ├── WDB2.cs │ │ ├── WDB5.cs │ │ ├── WDB6.cs │ │ ├── WDBC.cs │ │ ├── WDC1.cs │ │ ├── WDC2.cs │ │ └── WDC3.cs │ ├── MemoryReader.cs │ ├── RelationShipData.cs │ └── StringTable.cs ├── Resources │ ├── LoadDef.png │ ├── close.png │ ├── csv.png │ ├── hide.png │ ├── icon.ico │ ├── open-new.png │ ├── open.png │ ├── paintbrush.png │ ├── reload.png │ ├── save_file.png │ ├── search.png │ ├── sql.png │ ├── sqlfile.png │ ├── table.png │ ├── target.png │ ├── tick.png │ └── toggle.png ├── Storage │ ├── DBEntry.cs │ ├── Database.cs │ └── Definition.cs ├── UpdateManager.cs ├── WDBXEditor.csproj ├── packages.config ├── x64 │ └── StormLib.dll └── x86 │ └── StormLib.dll └── appveyor.yml /.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 | -------------------------------------------------------------------------------- /.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 | Changes.txt 10 | 11 | # User-specific files (MonoDevelop/Xamarin Studio) 12 | *.userprefs 13 | 14 | # Build results 15 | [Dd]ebug/ 16 | [Dd]ebugPublic/ 17 | [Rr]elease/ 18 | [Rr]eleases/ 19 | bld/ 20 | [Bb]in/ 21 | [Oo]bj/ 22 | [Ll]og/ 23 | 24 | # Visual Studio 2015 cache/options directory 25 | .vs/ 26 | # Uncomment if you have tasks that create the project's static files in wwwroot 27 | #wwwroot/ 28 | 29 | # MSTest test Results 30 | [Tt]est[Rr]esult*/ 31 | [Bb]uild[Ll]og.* 32 | 33 | # NUNIT 34 | *.VisualState.xml 35 | TestResult.xml 36 | 37 | # Build Results of an ATL Project 38 | [Dd]ebugPS/ 39 | [Rr]eleasePS/ 40 | dlldata.c 41 | 42 | # DNX 43 | project.lock.json 44 | artifacts/ 45 | 46 | *_i.c 47 | *_p.c 48 | *_i.h 49 | *.ilk 50 | *.meta 51 | *.obj 52 | *.pch 53 | *.pdb 54 | *.pgc 55 | *.pgd 56 | *.rsp 57 | *.sbr 58 | *.tlb 59 | *.tli 60 | *.tlh 61 | *.tmp 62 | *.tmp_proj 63 | *.log 64 | *.vspscc 65 | *.vssscc 66 | .builds 67 | *.pidb 68 | *.svclog 69 | *.scc 70 | 71 | # Chutzpah Test files 72 | _Chutzpah* 73 | 74 | # Visual C++ cache files 75 | ipch/ 76 | *.aps 77 | *.ncb 78 | *.opendb 79 | *.opensdf 80 | *.sdf 81 | *.cachefile 82 | *.VC.db 83 | *.VC.VC.opendb 84 | 85 | # Visual Studio profiler 86 | *.psess 87 | *.vsp 88 | *.vspx 89 | *.sap 90 | 91 | # TFS 2012 Local Workspace 92 | $tf/ 93 | 94 | # Guidance Automation Toolkit 95 | *.gpState 96 | 97 | # ReSharper is a .NET coding add-in 98 | _ReSharper*/ 99 | *.[Rr]e[Ss]harper 100 | *.DotSettings.user 101 | 102 | # JustCode is a .NET coding add-in 103 | .JustCode 104 | 105 | # TeamCity is a build add-in 106 | _TeamCity* 107 | 108 | # DotCover is a Code Coverage Tool 109 | *.dotCover 110 | 111 | # NCrunch 112 | _NCrunch_* 113 | .*crunch*.local.xml 114 | nCrunchTemp_* 115 | 116 | # MightyMoose 117 | *.mm.* 118 | AutoTest.Net/ 119 | 120 | # Web workbench (sass) 121 | .sass-cache/ 122 | 123 | # Installshield output folder 124 | [Ee]xpress/ 125 | 126 | # DocProject is a documentation generator add-in 127 | DocProject/buildhelp/ 128 | DocProject/Help/*.HxT 129 | DocProject/Help/*.HxC 130 | DocProject/Help/*.hhc 131 | DocProject/Help/*.hhk 132 | DocProject/Help/*.hhp 133 | DocProject/Help/Html2 134 | DocProject/Help/html 135 | 136 | # Click-Once directory 137 | publish/ 138 | 139 | # Publish Web Output 140 | *.[Pp]ublish.xml 141 | *.azurePubxml 142 | # TODO: Comment the next line if you want to checkin your web deploy settings 143 | # but database connection strings (with potential passwords) will be unencrypted 144 | *.pubxml 145 | *.publishproj 146 | 147 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 148 | # checkin your Azure Web App publish settings, but sensitive information contained 149 | # in these scripts will be unencrypted 150 | PublishScripts/ 151 | 152 | # NuGet Packages 153 | *.nupkg 154 | # The packages folder can be ignored because of Package Restore 155 | **/packages/* 156 | # except build/, which is used as an MSBuild target. 157 | !**/packages/build/ 158 | # Uncomment if necessary however generally it will be regenerated when needed 159 | #!**/packages/repositories.config 160 | # NuGet v3's project.json files produces more ignoreable files 161 | *.nuget.props 162 | *.nuget.targets 163 | 164 | # Microsoft Azure Build Output 165 | csx/ 166 | *.build.csdef 167 | 168 | # Microsoft Azure Emulator 169 | ecf/ 170 | rcf/ 171 | 172 | # Windows Store app package directories and files 173 | AppPackages/ 174 | BundleArtifacts/ 175 | Package.StoreAssociation.xml 176 | _pkginfo.txt 177 | 178 | # Visual Studio cache files 179 | # files ending in .cache can be ignored 180 | *.[Cc]ache 181 | # but keep track of directories ending in .cache 182 | !*.[Cc]ache/ 183 | 184 | # Others 185 | ClientBin/ 186 | ~$* 187 | *~ 188 | *.dbmdl 189 | *.dbproj.schemaview 190 | *.pfx 191 | *.publishsettings 192 | node_modules/ 193 | orleans.codegen.cs 194 | 195 | # Since there are multiple workflows, uncomment next line to ignore bower_components 196 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 197 | #bower_components/ 198 | 199 | # RIA/Silverlight projects 200 | Generated_Code/ 201 | 202 | # Backup & report files from converting an old project file 203 | # to a newer Visual Studio version. Backup files are not needed, 204 | # because we have git ;-) 205 | _UpgradeReport_Files/ 206 | Backup*/ 207 | UpgradeLog*.XML 208 | UpgradeLog*.htm 209 | 210 | # SQL Server files 211 | *.mdf 212 | *.ldf 213 | 214 | # Business Intelligence projects 215 | *.rdl.data 216 | *.bim.layout 217 | *.bim_*.settings 218 | 219 | # Microsoft Fakes 220 | FakesAssemblies/ 221 | 222 | # GhostDoc plugin setting file 223 | *.GhostDoc.xml 224 | 225 | # Node.js Tools for Visual Studio 226 | .ntvs_analysis.dat 227 | 228 | # Visual Studio 6 build log 229 | *.plg 230 | 231 | # Visual Studio 6 workspace options file 232 | *.opt 233 | 234 | # Visual Studio LightSwitch build output 235 | **/*.HTMLClient/GeneratedArtifacts 236 | **/*.DesktopClient/GeneratedArtifacts 237 | **/*.DesktopClient/ModelManifest.xml 238 | **/*.Server/GeneratedArtifacts 239 | **/*.Server/ModelManifest.xml 240 | _Pvt_Extensions 241 | 242 | # Paket dependency manager 243 | .paket/paket.exe 244 | paket-files/ 245 | 246 | # FAKE - F# Make 247 | .fake/ 248 | 249 | # JetBrains Rider 250 | .idea/ 251 | *.sln.iml 252 | .vscode/settings.json 253 | -------------------------------------------------------------------------------- /AdvancedDataGridView/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinsch/WDBXEditor/c4b7f1bea74a5ac98d0066885981ca2c5a58e95d/AdvancedDataGridView/Properties/AssemblyInfo.cs -------------------------------------------------------------------------------- /AdvancedDataGridView/Resources/Images/ColumnHeader_Filtered.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinsch/WDBXEditor/c4b7f1bea74a5ac98d0066885981ca2c5a58e95d/AdvancedDataGridView/Resources/Images/ColumnHeader_Filtered.png -------------------------------------------------------------------------------- /AdvancedDataGridView/Resources/Images/ColumnHeader_FilteredAndOrderedASC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinsch/WDBXEditor/c4b7f1bea74a5ac98d0066885981ca2c5a58e95d/AdvancedDataGridView/Resources/Images/ColumnHeader_FilteredAndOrderedASC.png -------------------------------------------------------------------------------- /AdvancedDataGridView/Resources/Images/ColumnHeader_FilteredAndOrderedDESC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinsch/WDBXEditor/c4b7f1bea74a5ac98d0066885981ca2c5a58e95d/AdvancedDataGridView/Resources/Images/ColumnHeader_FilteredAndOrderedDESC.png -------------------------------------------------------------------------------- /AdvancedDataGridView/Resources/Images/ColumnHeader_OrderedASC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinsch/WDBXEditor/c4b7f1bea74a5ac98d0066885981ca2c5a58e95d/AdvancedDataGridView/Resources/Images/ColumnHeader_OrderedASC.png -------------------------------------------------------------------------------- /AdvancedDataGridView/Resources/Images/ColumnHeader_OrderedDESC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinsch/WDBXEditor/c4b7f1bea74a5ac98d0066885981ca2c5a58e95d/AdvancedDataGridView/Resources/Images/ColumnHeader_OrderedDESC.png -------------------------------------------------------------------------------- /AdvancedDataGridView/Resources/Images/ColumnHeader_UnFiltered.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinsch/WDBXEditor/c4b7f1bea74a5ac98d0066885981ca2c5a58e95d/AdvancedDataGridView/Resources/Images/ColumnHeader_UnFiltered.png -------------------------------------------------------------------------------- /AdvancedDataGridView/Resources/Images/MenuStrip_OrderASCtxt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinsch/WDBXEditor/c4b7f1bea74a5ac98d0066885981ca2c5a58e95d/AdvancedDataGridView/Resources/Images/MenuStrip_OrderASCtxt.png -------------------------------------------------------------------------------- /AdvancedDataGridView/Resources/Images/MenuStrip_OrderDESCtxt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinsch/WDBXEditor/c4b7f1bea74a5ac98d0066885981ca2c5a58e95d/AdvancedDataGridView/Resources/Images/MenuStrip_OrderDESCtxt.png -------------------------------------------------------------------------------- /AdvancedDataGridView/Resources/Images/MenuStrip_ResizeGrip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinsch/WDBXEditor/c4b7f1bea74a5ac98d0066885981ca2c5a58e95d/AdvancedDataGridView/Resources/Images/MenuStrip_ResizeGrip.png -------------------------------------------------------------------------------- /Help/CommandLine.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Command Line 6 | 7 | 8 | 15 | 16 | 17 | 18 | 19 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 54 |
51 |
WDBX 52 | Editor Help
53 |
Command Line
Previous Next
55 | 56 |
57 |
58 |

Command Line Arguments

59 | 60 | Console Mode 61 |

62 | Opens the editor in a console window. Type help to see a list of commands. 63 |
64 | Arguments: 65 |

70 |
71 | Example: -console 72 |

73 | 74 | 75 | Extract 76 |

77 | Extracts files matching the file filter from either an MPQ archive or a CASC directory. 78 |
79 | Arguments: 80 |

89 |
90 | Example: -extract -f "*.dbc" -s "E:\WoW\Data\Patch-3.mpq" -o "C:\WotLK\" 91 |

92 | 93 | Export 94 |

95 | Exports a specific file to either CSV, JSON or a SQL file. 96 |
97 | Arguments: 98 |

109 |
110 | Example: -export -f "Achievement.dbc" -s "E:\WoW\Data\Patch-3.mpq" -b 11802 -o "Achievement.csv" 111 |

112 | 113 | SQL Dump 114 |

115 | Dumps a specific file's data into a MySQL database. 116 |
117 | Arguments: 118 |

129 |
130 | Example: -sqldump -f "Achievement.dbc" -s "E:\WoW\Data\Patch-3.mpq" -b 11802 -c "Server=myServerAddress;Database=myDataBase;Uid=myUsername;Pwd=myPassword;" 131 |

132 | 133 |


134 | 135 |
136 | 137 |

138 |

Previous Next

139 | 140 | 141 | -------------------------------------------------------------------------------- /Help/DataGrid.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Tools 6 | 7 | 8 | 15 | 16 | 17 | 18 | 19 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 54 |
51 |
WDBX 52 | Editor Help
53 |
Data Grid
Previous Next
55 | 56 |
57 |
58 |

Custom Header

59 |

The data grid has been custom built to support basic actions that should be included in any grid based program. These include: 60 |

66 |

67 | 68 |

Column Filter

69 |

The column filter allows the hiding of any specified columns and the option to restore all, this is particularly useful for localised strings in older DBC files when you are only working with one locale. This state is reset everytime the current file being edited is changed

70 | 71 |
72 | 73 |

74 |

Previous Next

75 | 76 | 77 | -------------------------------------------------------------------------------- /Help/FindReplace.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Tools 6 | 7 | 8 | 15 | 16 | 17 | 18 | 19 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 54 |
51 |
WDBX 52 | Editor Help
53 |
Find and Replace
Previous Next
55 | 56 |
57 |
58 |

Find and Replace

59 |

The Find and Replace window is designed to stay active when used and changes opacity in a similar fashion to Notepad++. There are several search options that are available: 60 |

65 |

66 | 67 |
68 | 69 |

70 |

Previous Next

71 | 72 | 73 | -------------------------------------------------------------------------------- /Help/Help.chm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinsch/WDBXEditor/c4b7f1bea74a5ac98d0066885981ca2c5a58e95d/Help/Help.chm -------------------------------------------------------------------------------- /Help/Help.hhp: -------------------------------------------------------------------------------- 1 | [OPTIONS] 2 | Compatibility=1.1 or later 3 | Compiled file=Help.chm 4 | Contents file=help.hhc 5 | Default topic=Introduction.htm 6 | Display compile progress=No 7 | Index file=help.hhk 8 | Language=0x809 English (United Kingdom) 9 | 10 | 11 | [FILES] 12 | Import_Export.htm 13 | Introduction.htm 14 | Menu_Items.htm 15 | Tools.htm 16 | DataGrid.htm 17 | FindReplace.htm 18 | 19 | [INFOTYPES] 20 | 21 | -------------------------------------------------------------------------------- /Help/Images/DataGrid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinsch/WDBXEditor/c4b7f1bea74a5ac98d0066885981ca2c5a58e95d/Help/Images/DataGrid.png -------------------------------------------------------------------------------- /Help/Images/Definition Editor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinsch/WDBXEditor/c4b7f1bea74a5ac98d0066885981ca2c5a58e95d/Help/Images/Definition Editor.png -------------------------------------------------------------------------------- /Help/Images/Definition Selector.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinsch/WDBXEditor/c4b7f1bea74a5ac98d0066885981ca2c5a58e95d/Help/Images/Definition Selector.png -------------------------------------------------------------------------------- /Help/Images/FindReplace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinsch/WDBXEditor/c4b7f1bea74a5ac98d0066885981ca2c5a58e95d/Help/Images/FindReplace.png -------------------------------------------------------------------------------- /Help/Images/SQL Import.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinsch/WDBXEditor/c4b7f1bea74a5ac98d0066885981ca2c5a58e95d/Help/Images/SQL Import.png -------------------------------------------------------------------------------- /Help/Import_Export.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Import Export 6 | 7 | 8 | 15 | 16 | 17 | 18 | 19 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 54 |
51 |
WDBX 52 | Editor Help
53 |
Import Export
Previous Next
55 | 56 |
57 |
58 |

Export

59 |

To SQL - When exporting directly to a database, the system will create a 60 | table named `db_<FileName>` which is then populated using the MySQL Bulk 61 | Copy which is faster than importing a SQL file.

62 |

To SQL File - This will generate a MySQL formatted file

63 |

To CSV - This will produce a comma seperated file, with escaped strings

64 |

To MPQ - This will export the selected file to an MPQ archive, if an existing 65 | archive is selected then the file will be appended to it otherwise a new archive 66 | will be created

67 |

Import

68 |

From SQL - This will import data directly from a MySQL database

69 |

From CSV

70 |

Import Notes:

71 |



78 | 79 |
80 | 81 |

82 |

Previous Next

83 | 84 | 85 | -------------------------------------------------------------------------------- /Help/Introduction.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Introduction 6 | 7 | 8 | 15 | 16 | 17 | 18 | 19 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 54 |
51 |
WDBX 52 | Editor Help
53 |
Introduction
 Next
55 | 56 |
57 |
58 |

WDBX Editor is an editor designed to open all release 59 | client database files implemented in World of Warcraft clients.

60 |

The currently supported file formats are:

61 | 70 |

The editor works with all versions of World of Warcraft 71 | ranging from the Alpha (0.5.3) up to the latest build of Legion.

72 |

The base editor features includes:

73 | 87 |

I've included some functionality around 88 | Importing, Exporting and also some tools to help do common tasks. The data grid itself has also been custom built to implement common grid features.

89 | 90 |

The application works as a single instance so all files will open within the original instance of the program. There is however an option to open new files in a new instance. The program also has command line arguments which can be utalised with batch scripts and provides integration into other systems.

91 | 92 |


93 | 94 |
95 | 96 |

97 |

 Next

98 | 99 | 100 | -------------------------------------------------------------------------------- /Help/Main Screen/btn_next_n.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinsch/WDBXEditor/c4b7f1bea74a5ac98d0066885981ca2c5a58e95d/Help/Main Screen/btn_next_n.gif -------------------------------------------------------------------------------- /Help/Main Screen/btn_prev_n.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinsch/WDBXEditor/c4b7f1bea74a5ac98d0066885981ca2c5a58e95d/Help/Main Screen/btn_prev_n.gif -------------------------------------------------------------------------------- /Help/Notes.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Tools 6 | 7 | 8 | 15 | 16 | 17 | 18 | 19 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 54 |
51 |
WDBX 52 | Editor Help
53 |
Tips and Notes
Previous 
55 | 56 |
57 |
58 |

Tips and Notes

59 |

Some things to remember and note: 60 |

71 |

72 | 73 |
74 | 75 |

76 |

Previous 

77 | 78 | 79 | -------------------------------------------------------------------------------- /Help/Tools.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Tools 6 | 7 | 8 | 15 | 16 | 17 | 18 | 19 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 54 |
51 |
WDBX 52 | Editor Help
53 |
Tools
Previous Next
55 | 56 |
57 |
58 |

Defintion Editor

59 |

The definition editor allows the ability to create, edit 60 | and delete defintions.

61 |

These can also be created and 62 | edited manually. Any *.xml files in the Definition will be imported 63 | provided they meet the basic rules of being named correctly and having a single 64 | int32 ID column.

65 |

Available Types:

66 | 90 |

There are also a number of additional settings that are 91 | rarely used.

92 |


103 | 104 |
105 | 106 |

107 |

Previous Next

108 | 109 | 110 | -------------------------------------------------------------------------------- /Help/help.hhc: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 55 | 56 | -------------------------------------------------------------------------------- /Help/help.hhk: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WDBX Editor 2 | 3 | ### About 4 | This editor has full support for reading and saving all release versions of DBC, DB2, WDB, ADB and DBCache. This does include support for Legion DB2 and DBCache files and works with all variants (header flags) of these. 5 | Like the other editors I've used a definition based system whereby definitions tell the editor how to interpret each file's columns - this is a lot more reliable than guessing column types but does mean the definitions must be maintained. So far, I've mapped almost all expansions with MoP being ~50% complete and everything else being 99%+ (excluding column names). 6 | 7 | You will need [Microsoft .NET Framework 4.6.1](https://www.microsoft.com/en-us/download/details.aspx?id=49982) to run this application 8 | 9 | ### Features: 10 | * Full support of release versions of DBC, DB2, WDB, ADB and DBCache (WCH3 and WCH4 are not supported as I deem them depreciated) 11 | * Supports being the default file assocation 12 | * Opening and having open multiple files regardless of type and build 13 | * Open DBC/DB2 files from both MPQ archives and CASC directories 14 | * Save single (to file) and save all (to folder) 15 | * Standard CRUD operations as well as go to, copy row, paste row, undo and redo 16 | * Hide, show, hide empty and sort columns 17 | * A relatively powerful column filter system (similar to boolean search) 18 | * Displaying and editing columns in hex (numeric columns only) 19 | * Exporting to a SQL database, SQL file, CSV file and MPQ archives 20 | * Importing from a SQL database and a CSV file 21 | * An Excel style Find and Replace 22 | * Shortcuts for common tasks using common shortcut key combinations 23 | * A help file to try and cover off some of the pitfalls and caveats of the program (needs some work) 24 | * A simple memory reader to get player's co-ordinates from the client 25 | * A colour picker for LightData and LightIntBand 26 | 27 | ### Tools: 28 | * Definition editor for maintaining the definitions 29 | * WotLK Item Import to remove the dreaded red question mark from custom items 30 | * Legion Parser which is an attempt to automatically parse the structure of WDB5 and WDB6 files 31 | 32 | ### Project Goal: 33 | The goal of this project is to create a communal program that is compatible with all file variants, is feature rich and negates the need to use multiple different programs. 34 | This means any and all contribution in the form of commits, change requests, issues etc are more than welcome! 35 | 36 | ### Credits: 37 | Credits go to Ladislav Zezula for the awesome StormLib and thanks to all those that contribute to the WoWDev wiki. 38 | I've also patched the definitions together for various sources across the internet, there are too many to name, but thanks to all. 39 | -------------------------------------------------------------------------------- /Run on Linux.md: -------------------------------------------------------------------------------- 1 | ## Run WDBX on Ubuntu with wine 2 | 3 | Install last version of wine from this guide: https://tecadmin.net/install-wine-on-ubuntu/ 4 | 5 | Install also winetricks using: 6 | ``` 7 | $ sudo apt install winetricks 8 | ``` 9 | 10 | Delete all previous dotnet versions that you have installed and run: 11 | 12 | ``` 13 | $ winetricks 14 | ``` 15 | 16 | Running winetricks, Wine Mono Installer will appear, just wait and install. 17 | This will solve the following error: 18 | ``` 19 | 0009:err:mscoree:CLRRuntimeInfo_GetRuntimeHost Wine Mono is not installed 20 | ``` 21 | 22 | 23 | Run: 24 | ``` 25 | winetricks dotnet461 26 | ``` 27 | 28 | Here you go, now you can run WDBX.exe 29 | 30 | 31 | ## Troubleshooting: 32 | 33 | If **Wine Mono Installer** does not appear or you get some errors, try to clean everything about wine and winetricks using: 34 | ``` 35 | $ winetricks 36 | ``` 37 | - `Select the default wineprefix` 38 | - `Install a Windows DLL or component` 39 | - last option `Delete ALL DATA AND APPLICATIONS INSIDE THIS WINEPREFIX` <-- be careful, this will delete everything inside your ~/.wine directory. 40 | - follow again the steps 41 | 42 | 43 | ### Credits 44 | 45 | - [Helias](https://github.com/Helias) 46 | 47 | Tested with wine 4.0.2, Ubuntu 18.04.3 LTS and with [WDBX 1.1.9a](https://github.com/WowDevTools/WDBXEditor/releases/tag/1.1.9.a) 48 | -------------------------------------------------------------------------------- /UpdateDBC.bat: -------------------------------------------------------------------------------- 1 | SET WDBX="C:\WDBXEditor\WDBX Editor.exe" 2 | 3 | FOR %%A IN (%*) DO %WDBX% -sqlload -f %%A -b 12340 -m 2 -c "Server=127.0.0.1;Database=database;Uid=trinity;Pwd=trinity;" -------------------------------------------------------------------------------- /WDBXEditor.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27130.2036 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WDBXEditor", "WDBXEditor\WDBXEditor.csproj", "{E1F42B5C-7A40-4539-AD92-E24CAD7041F5}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AdvancedDataGridView", "AdvancedDataGridView\AdvancedDataGridView.csproj", "{6EBA0A55-B390-4479-A564-58D46094998D}" 9 | EndProject 10 | Global 11 | GlobalSection(Performance) = preSolution 12 | HasPerformanceSessions = true 13 | EndGlobalSection 14 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 15 | Debug|Any CPU = Debug|Any CPU 16 | Debug|x64 = Debug|x64 17 | Release|Any CPU = Release|Any CPU 18 | Release|x64 = Release|x64 19 | EndGlobalSection 20 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 21 | {E1F42B5C-7A40-4539-AD92-E24CAD7041F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 22 | {E1F42B5C-7A40-4539-AD92-E24CAD7041F5}.Debug|Any CPU.Build.0 = Debug|Any CPU 23 | {E1F42B5C-7A40-4539-AD92-E24CAD7041F5}.Debug|x64.ActiveCfg = Debug|x64 24 | {E1F42B5C-7A40-4539-AD92-E24CAD7041F5}.Debug|x64.Build.0 = Debug|x64 25 | {E1F42B5C-7A40-4539-AD92-E24CAD7041F5}.Release|Any CPU.ActiveCfg = Release|Any CPU 26 | {E1F42B5C-7A40-4539-AD92-E24CAD7041F5}.Release|Any CPU.Build.0 = Release|Any CPU 27 | {E1F42B5C-7A40-4539-AD92-E24CAD7041F5}.Release|x64.ActiveCfg = Release|x64 28 | {E1F42B5C-7A40-4539-AD92-E24CAD7041F5}.Release|x64.Build.0 = Release|x64 29 | {6EBA0A55-B390-4479-A564-58D46094998D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 30 | {6EBA0A55-B390-4479-A564-58D46094998D}.Debug|Any CPU.Build.0 = Debug|Any CPU 31 | {6EBA0A55-B390-4479-A564-58D46094998D}.Debug|x64.ActiveCfg = Debug|x64 32 | {6EBA0A55-B390-4479-A564-58D46094998D}.Debug|x64.Build.0 = Debug|x64 33 | {6EBA0A55-B390-4479-A564-58D46094998D}.Release|Any CPU.ActiveCfg = Release|Any CPU 34 | {6EBA0A55-B390-4479-A564-58D46094998D}.Release|Any CPU.Build.0 = Release|Any CPU 35 | {6EBA0A55-B390-4479-A564-58D46094998D}.Release|x64.ActiveCfg = Release|x64 36 | {6EBA0A55-B390-4479-A564-58D46094998D}.Release|x64.Build.0 = Release|x64 37 | EndGlobalSection 38 | GlobalSection(SolutionProperties) = preSolution 39 | HideSolutionNode = FALSE 40 | EndGlobalSection 41 | GlobalSection(ExtensibilityGlobals) = postSolution 42 | SolutionGuid = {645EB3D9-4619-4DF0-BDC5-9A0B95065969} 43 | EndGlobalSection 44 | EndGlobal 45 | -------------------------------------------------------------------------------- /WDBXEditor/About.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace WDBXEditor 2 | { 3 | partial class About 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(About)); 32 | this.imgLogo = new System.Windows.Forms.PictureBox(); 33 | this.txtAbout = new System.Windows.Forms.RichTextBox(); 34 | ((System.ComponentModel.ISupportInitialize)(this.imgLogo)).BeginInit(); 35 | this.SuspendLayout(); 36 | // 37 | // imgLogo 38 | // 39 | this.imgLogo.BackColor = System.Drawing.SystemColors.Control; 40 | this.imgLogo.Image = ((System.Drawing.Image)(resources.GetObject("imgLogo.Image"))); 41 | this.imgLogo.Location = new System.Drawing.Point(12, 12); 42 | this.imgLogo.Name = "imgLogo"; 43 | this.imgLogo.Size = new System.Drawing.Size(40, 40); 44 | this.imgLogo.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage; 45 | this.imgLogo.TabIndex = 0; 46 | this.imgLogo.TabStop = false; 47 | // 48 | // txtAbout 49 | // 50 | this.txtAbout.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 51 | | System.Windows.Forms.AnchorStyles.Left) 52 | | System.Windows.Forms.AnchorStyles.Right))); 53 | this.txtAbout.BorderStyle = System.Windows.Forms.BorderStyle.None; 54 | this.txtAbout.Enabled = false; 55 | this.txtAbout.Location = new System.Drawing.Point(58, 12); 56 | this.txtAbout.Name = "txtAbout"; 57 | this.txtAbout.ReadOnly = true; 58 | this.txtAbout.Size = new System.Drawing.Size(289, 99); 59 | this.txtAbout.TabIndex = 1; 60 | this.txtAbout.Text = "WDBX Editor\n\nCreated by Barncastle © 2016\n\nCredits to Ladislav Zezula for the awe" + 61 | "some StormLib\n\nThanks to everyone that contributes to the WoWDev wiki"; 62 | // 63 | // About 64 | // 65 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 66 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 67 | this.ClientSize = new System.Drawing.Size(348, 113); 68 | this.Controls.Add(this.txtAbout); 69 | this.Controls.Add(this.imgLogo); 70 | this.MaximizeBox = false; 71 | this.MinimizeBox = false; 72 | this.Name = "About"; 73 | this.ShowIcon = false; 74 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; 75 | this.Text = "About"; 76 | ((System.ComponentModel.ISupportInitialize)(this.imgLogo)).EndInit(); 77 | this.ResumeLayout(false); 78 | 79 | } 80 | 81 | #endregion 82 | 83 | private System.Windows.Forms.PictureBox imgLogo; 84 | private System.Windows.Forms.RichTextBox txtAbout; 85 | } 86 | } -------------------------------------------------------------------------------- /WDBXEditor/About.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows.Forms; 10 | 11 | namespace WDBXEditor 12 | { 13 | public partial class About : Form 14 | { 15 | public About() 16 | { 17 | InitializeComponent(); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /WDBXEditor/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 3306 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | https://github.com/WowDevTools/WDBXEditor/releases 34 | 35 | 36 | http://api.github.com/repos/WowDevTools/WDBXEditor/releases/latest 37 | 38 | 39 | Mozilla/4.0 (Compatible; Windows NT 5.1; MSIE 6.0) (compatible; MSIE 6.0; Windows NT 5.1; WDBXEditor 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /WDBXEditor/Archives/CASC/Constants/Locales.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace WDBXEditor.Archives.CASC.Constants 4 | { 5 | [Flags] 6 | public enum Locales : uint 7 | { 8 | All = 0xFFFFFFFF, 9 | None = 0, 10 | EnUS = 0x2, 11 | KoKR = 0x4, 12 | FrFR = 0x10, 13 | DeDE = 0x20, 14 | ZhCN = 0x40, 15 | EsES = 0x80, 16 | ZhTW = 0x100, 17 | EnGB = 0x200, 18 | EnCN = 0x400, 19 | EnTW = 0x800, 20 | EsMX = 0x1000, 21 | RuRU = 0x2000, 22 | PtBR = 0x4000, 23 | ItIT = 0x8000, 24 | PtPT = 0x10000, 25 | All_WoW = EnUS | KoKR | FrFR | DeDE | ZhCN | EsES | ZhTW | EnGB | EsMX | RuRU | PtBR | ItIT | PtPT 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /WDBXEditor/Archives/CASC/Handlers/BuildConfig.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using WDBXEditor.Archives.Misc; 5 | 6 | namespace WDBXEditor.Archives.FileSystem.Structures 7 | { 8 | public class BuildConfig 9 | { 10 | public string[] this[string name] 11 | { 12 | get 13 | { 14 | string[] entry; 15 | 16 | if (entries.TryGetValue(name, out entry)) 17 | return entry; 18 | 19 | return null; 20 | } 21 | } 22 | 23 | Dictionary entries = new Dictionary(); 24 | 25 | public BuildConfig(string wowPath, string buildKey) 26 | { 27 | using (var sr = new StreamReader($"{wowPath}/Data/config/{buildKey.GetHexAt(0)}/{buildKey.GetHexAt(2)}/{buildKey}")) 28 | { 29 | while (!sr.EndOfStream) 30 | { 31 | var data = sr.ReadLine().Split(new[] { '=' }, StringSplitOptions.RemoveEmptyEntries); 32 | 33 | if (data.Length < 2) 34 | continue; 35 | 36 | var key = data[0].Trim(); 37 | var value = data[1].Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); 38 | 39 | entries.Add(key, value); 40 | } 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /WDBXEditor/Archives/CASC/Handlers/BuildInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | 5 | namespace WDBXEditor.Archives.CASC.Handlers 6 | { 7 | public class BuildInfo 8 | { 9 | public string this[string name] 10 | { 11 | get 12 | { 13 | string entry; 14 | if (entries.TryGetValue(name, out entry)) 15 | return entry; 16 | 17 | return null; 18 | } 19 | } 20 | 21 | Dictionary entries = new Dictionary(); 22 | 23 | public BuildInfo(string file) 24 | { 25 | using (var sr = new StreamReader(file)) 26 | { 27 | var header = sr.ReadLine().Split(new[] { '|', '!' }); 28 | var dataLine = ""; 29 | 30 | while ((dataLine = sr.ReadLine()) != null) 31 | { 32 | var data = dataLine.Split(new[] { '|' }); 33 | 34 | if (data.Length != header.Length / 2) 35 | throw new InvalidOperationException("Invalid header length"); 36 | 37 | // Be sure to get the active build info. 38 | if (data[1] == "0") 39 | continue; 40 | 41 | for (var i = 0; i < data.Length; i++) 42 | entries.Add(header[i << 1], data[i]); 43 | } 44 | } 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /WDBXEditor/Archives/CASC/Handlers/CDNConfig.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using WDBXEditor.Archives.CASC.Structures; 5 | using WDBXEditor.Archives.Misc; 6 | 7 | namespace WDBXEditor.Archives.CASC.Handlers 8 | { 9 | class CDNConfig 10 | { 11 | public string[] this[string name] 12 | { 13 | get 14 | { 15 | string[] entry; 16 | 17 | if (entries.TryGetValue(name, out entry)) 18 | return entry; 19 | 20 | return null; 21 | } 22 | } 23 | 24 | public string Host { get; set; } 25 | public string Path { get; set; } 26 | public string DownloadUrl => Host + Path; 27 | 28 | Dictionary entries = new Dictionary(); 29 | 30 | public CDNConfig(string wowPath, string buildKey) 31 | { 32 | using (var sr = new StreamReader($"{wowPath}/Data/config/{buildKey.GetHexAt(0)}/{buildKey.GetHexAt(2)}/{buildKey}")) 33 | { 34 | while (!sr.EndOfStream) 35 | { 36 | var data = sr.ReadLine().Split(new[] { '=' }, StringSplitOptions.RemoveEmptyEntries); 37 | if (data.Length < 2) 38 | continue; 39 | 40 | var key = data[0].Trim(); 41 | var value = data[1].Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); 42 | 43 | entries.Add(key, value); 44 | } 45 | } 46 | } 47 | 48 | public BinaryReader DownloadFile(string archive, IndexEntry indexEntry) 49 | { 50 | throw new NotImplementedException("Client data folder is incomplete."); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /WDBXEditor/Archives/CASC/Handlers/DataFile.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.IO; 3 | using System.IO.Compression; 4 | using WDBXEditor.Archives.CASC.Structures; 5 | using WDBXEditor.Archives.Misc; 6 | 7 | namespace WDBXEditor.Archives.CASC.Handlers 8 | { 9 | public class DataFile 10 | { 11 | public readonly BinaryReader readStream; 12 | 13 | static object readLock = new object(); 14 | 15 | public DataFile(Stream data) 16 | { 17 | readStream = new BinaryReader(data); 18 | } 19 | 20 | public static MemoryStream LoadBLTEEntry(IndexEntry idxEntry, BinaryReader readStream = null) 21 | { 22 | lock (readLock) 23 | { 24 | if (readStream == null) 25 | return null; 26 | 27 | readStream.BaseStream.Position = idxEntry.Offset + 30; 28 | 29 | if (readStream.ReadUInt32() != 0x45544C42) 30 | { 31 | Trace.TraceError($"data.{idxEntry.Index:000}: Invalid BLTE signature at 0x{readStream.BaseStream.Position:X8}."); 32 | 33 | return null; 34 | } 35 | 36 | var blte = new BLTEEntry(); 37 | var frameHeaderLength = readStream.ReadBEUInt32(); 38 | var chunks = 0u; 39 | var size = 0L; 40 | 41 | if (frameHeaderLength == 0) 42 | { 43 | chunks = 1; 44 | size = idxEntry.Size - 38; 45 | } 46 | else 47 | { 48 | readStream.BaseStream.Position += 1; 49 | 50 | chunks = readStream.ReadUInt24(); 51 | } 52 | 53 | blte.Chunks = new BLTEChunk[chunks]; 54 | 55 | for (var i = 0; i < chunks; i++) 56 | { 57 | if (frameHeaderLength == 0) 58 | { 59 | blte.Chunks[i].CompressedSize = size; 60 | blte.Chunks[i].UncompressedSize = size - 1; 61 | } 62 | else 63 | { 64 | blte.Chunks[i].CompressedSize = readStream.ReadBEUInt32(); 65 | blte.Chunks[i].UncompressedSize = readStream.ReadBEUInt32(); 66 | 67 | // Skip MD5 hash 68 | readStream.BaseStream.Position += 16; 69 | } 70 | } 71 | 72 | var data = new MemoryStream(); 73 | 74 | for (var i = 0; i < chunks; i++) 75 | { 76 | var formatCode = readStream.ReadByte(); 77 | var dataBytes = readStream.ReadBytes((int)blte.Chunks[i].CompressedSize - 1); 78 | 79 | // Not compressed 80 | if (formatCode == 0x4E) 81 | data.Write(dataBytes, 0, (int)blte.Chunks[i].UncompressedSize); 82 | // Compressed 83 | else if (formatCode == 0x5A) 84 | { 85 | using (var decompressed = new MemoryStream()) 86 | { 87 | using (var inflate = new DeflateStream(new MemoryStream(dataBytes, 2, dataBytes.Length - 2), CompressionMode.Decompress)) 88 | inflate.CopyTo(decompressed); 89 | 90 | var inflateData = decompressed.ToArray(); 91 | data.Write(inflateData, 0, inflateData.Length); 92 | } 93 | } 94 | } 95 | 96 | data.Position = 0; 97 | 98 | 99 | return data; 100 | } 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /WDBXEditor/Archives/CASC/Handlers/EncodingFile.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.IO; 3 | using WDBXEditor.Archives.CASC.Structures; 4 | using WDBXEditor.Archives.Misc; 5 | 6 | namespace WDBXEditor.Archives.CASC.Handlers 7 | { 8 | public class EncodingFile 9 | { 10 | public EncodingEntry this[byte[] md5] 11 | { 12 | get 13 | { 14 | EncodingEntry entry; 15 | 16 | if (entries.TryGetValue(md5, out entry)) 17 | return entry; 18 | 19 | return default(EncodingEntry); 20 | } 21 | } 22 | 23 | public byte[] Key { get; } 24 | 25 | Dictionary entries = new Dictionary(new ByteArrayComparer()); 26 | 27 | public EncodingFile(byte[] encodingKey) 28 | { 29 | Key = encodingKey.Slice(0, 9); 30 | } 31 | 32 | public void LoadEntries(DataFile file, IndexEntry indexEntry) 33 | { 34 | var blteEntry = new BinaryReader(DataFile.LoadBLTEEntry(indexEntry, file.readStream)); 35 | 36 | blteEntry.BaseStream.Position = 9; 37 | 38 | var entries = blteEntry.ReadBEUInt32(); 39 | 40 | blteEntry.BaseStream.Position += 5; 41 | 42 | var offsetEntries = blteEntry.ReadBEUInt32(); 43 | 44 | blteEntry.BaseStream.Position += offsetEntries + (entries << 5); 45 | 46 | for (var i = 0; i < entries; i++) 47 | { 48 | var keys = blteEntry.ReadUInt16(); 49 | 50 | while (keys != 0) 51 | { 52 | var encodingEntry = new EncodingEntry 53 | { 54 | Keys = new byte[keys][], 55 | Size = blteEntry.ReadBEUInt32() 56 | }; 57 | 58 | var md5 = blteEntry.ReadBytes(16); 59 | 60 | for (var j = 0; j < keys; j++) 61 | encodingEntry.Keys[j] = blteEntry.ReadBytes(16); 62 | 63 | this.entries.Add(md5, encodingEntry); 64 | 65 | keys = blteEntry.ReadUInt16(); 66 | } 67 | 68 | while (blteEntry.ReadByte() == 0); 69 | 70 | blteEntry.BaseStream.Position -= 1; 71 | } 72 | 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /WDBXEditor/Archives/CASC/Handlers/IndexFile.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.IO; 3 | using WDBXEditor.Archives.CASC.Structures; 4 | using WDBXEditor.Archives.Misc; 5 | 6 | namespace WDBXEditor.Archives.CASC.Handlers 7 | { 8 | public class IndexFile 9 | { 10 | public IndexEntry this[byte[] hash] 11 | { 12 | get 13 | { 14 | IndexEntry entry; 15 | 16 | if (entries.TryGetValue(hash, out entry)) 17 | return entry; 18 | 19 | return default(IndexEntry); 20 | } 21 | } 22 | 23 | public Dictionary entries = new Dictionary(new ByteArrayComparer()); 24 | 25 | public IndexFile(string idx, bool cdnIndex = false, ushort fileIndex = 0) 26 | { 27 | if (cdnIndex) 28 | { 29 | var nullHash = new byte[16]; 30 | 31 | using (var br = new BinaryReader(File.OpenRead(idx))) 32 | { 33 | br.BaseStream.Position = br.BaseStream.Length - 12; 34 | 35 | var entries = br.ReadUInt32(); 36 | 37 | br.BaseStream.Position = 0; 38 | 39 | for (var i = 0; i < entries; i++) 40 | { 41 | var hash = br.ReadBytes(16); 42 | 43 | if (hash.Compare(nullHash)) 44 | hash = br.ReadBytes(16); 45 | 46 | var entry = new IndexEntry 47 | { 48 | Index = fileIndex, 49 | Size = br.ReadBEUInt32(), 50 | Offset = br.ReadBEUInt32() 51 | }; 52 | 53 | if (this.entries.ContainsKey(hash)) 54 | continue; 55 | 56 | this.entries.Add(hash, entry); 57 | } 58 | } 59 | } 60 | else 61 | { 62 | using (var br = new BinaryReader(File.OpenRead(idx))) 63 | { 64 | br.BaseStream.Position = 0x20; 65 | 66 | var dataLength = br.ReadUInt32(); 67 | 68 | br.BaseStream.Position += 4; 69 | 70 | // 18 bytes per entry. 71 | for (var i = 0; i < dataLength / 18; i++) 72 | { 73 | var hash = br.ReadBytes(9); 74 | var index = br.ReadByte(); 75 | var offset = br.ReadBEUInt32(); 76 | 77 | var entry = new IndexEntry(); 78 | 79 | entry.Size = br.ReadUInt32(); 80 | entry.Index = (ushort)((ushort)(index << 2) | (offset >> 30)); 81 | entry.Offset = (uint)(offset & 0x3FFFFFFF); 82 | 83 | if (entries.ContainsKey(hash)) 84 | continue; 85 | 86 | entries.Add(hash, entry); 87 | } 88 | } 89 | } 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /WDBXEditor/Archives/CASC/Handlers/RootFile.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.IO; 3 | using System.Linq; 4 | using WDBXEditor.Archives.CASC.Constants; 5 | using WDBXEditor.Archives.CASC.Structures; 6 | 7 | namespace WDBXEditor.Archives.CASC.Handlers 8 | { 9 | public class RootFile 10 | { 11 | public ILookup Entries { get; private set; } 12 | 13 | public RootEntry[] this[ulong hash] => Entries.Contains(hash) ? Entries[hash].ToArray() : new RootEntry[0]; 14 | 15 | public void LoadEntries(DataFile file, IndexEntry indexEntry) 16 | { 17 | var list = new List(); 18 | var blteEntry = new BinaryReader(DataFile.LoadBLTEEntry(indexEntry, file.readStream)); 19 | 20 | while (blteEntry.BaseStream.Position < blteEntry.BaseStream.Length) 21 | { 22 | var entries = new RootEntry[blteEntry.ReadInt32()]; 23 | 24 | blteEntry.BaseStream.Position += 4; 25 | 26 | var locales = (Locales)blteEntry.ReadUInt32(); 27 | 28 | blteEntry.BaseStream.Position += (entries.Length << 2); 29 | 30 | for (var i = 0; i < entries.Length; i++) 31 | { 32 | list.Add(new RootEntry 33 | { 34 | MD5 = blteEntry.ReadBytes(16), 35 | Hash = blteEntry.ReadUInt64(), 36 | Locales = locales 37 | }); 38 | } 39 | } 40 | 41 | Entries = list.ToLookup(re => re.Hash); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /WDBXEditor/Archives/CASC/Misc/ByteArrayComparer.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | 4 | namespace WDBXEditor.Archives.Misc 5 | { 6 | public class ByteArrayComparer : IEqualityComparer, IEqualityComparer 7 | { 8 | public new bool Equals(object x, object y) 9 | { 10 | var eq = x as IStructuralEquatable; 11 | return eq == null ? object.Equals(x, y) : eq.Equals(y, this); 12 | } 13 | 14 | public int GetHashCode(object obj) 15 | { 16 | var eq = obj as IStructuralEquatable; 17 | return eq == null ? EqualityComparer.Default.GetHashCode(obj) : eq.GetHashCode(this); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /WDBXEditor/Archives/CASC/Misc/Extensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | 4 | namespace WDBXEditor.Archives.Misc 5 | { 6 | public static class Extensions 7 | { 8 | public static byte[] ToByteArray(this string s) 9 | { 10 | var data = new byte[s.Length / 2]; 11 | 12 | for (int i = 0; i < s.Length; i += 2) 13 | data[i / 2] = Convert.ToByte(s.Substring(i, 2), 16); 14 | 15 | return data; 16 | } 17 | 18 | public static string GetHexAt(this string value, int index) 19 | { 20 | var hex = Convert.ToByte(value.Substring(index, 2), 16); 21 | 22 | return $"{hex:x2}"; 23 | } 24 | 25 | public static bool Compare(this byte[] b, byte[] b2) 26 | { 27 | for (int i = 0; i < b2.Length; i++) 28 | if (b[i] != b2[i]) 29 | return false; 30 | 31 | return true; 32 | } 33 | 34 | public static T[] Slice(this T[] arr, int start, int end) 35 | { 36 | var newLength = end - start; 37 | var ret = new T[newLength]; 38 | 39 | for (var i = 0; i < newLength; i++) 40 | ret[i] = arr[start + i]; 41 | 42 | return ret; 43 | } 44 | 45 | public static ushort ReadBEUInt16(this BinaryReader br) 46 | { 47 | return (ushort)System.Net.IPAddress.HostToNetworkOrder(br.ReadInt16()); 48 | } 49 | 50 | public static uint ReadBEUInt32(this BinaryReader br) 51 | { 52 | return (uint)System.Net.IPAddress.HostToNetworkOrder(br.ReadInt32()); 53 | } 54 | 55 | public static uint ReadUInt24(this BinaryReader br) 56 | { 57 | var bytes = br.ReadBytes(3); 58 | 59 | return (uint)((bytes[0] << 16) | (bytes[1] << 8) | bytes[2]); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /WDBXEditor/Archives/CASC/Misc/Lookup3.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using System.Text; 4 | 5 | namespace WDBXEditor.Archives.Misc 6 | { 7 | public class Lookup3 8 | { 9 | public ulong Hash(string data) 10 | { 11 | data = data.Replace('/', '\\').ToUpperInvariant(); // fix string 12 | return Hash(Encoding.ASCII.GetBytes(data)); 13 | } 14 | 15 | public ulong Hash(byte[] data) 16 | { 17 | var length = data.Length; 18 | uint a, b, c; 19 | 20 | a = b = c = 0xdeadbeef + (uint)length; 21 | 22 | if ((data.Length % 12) != 0) 23 | Array.Resize(ref data, data.Length + (12 - (data.Length % 12))); 24 | 25 | var k = 0; 26 | 27 | while (length > 12) 28 | { 29 | var i = (k >> 2) << 2; 30 | 31 | a += BitConverter.ToUInt32(data, i); 32 | b += BitConverter.ToUInt32(data, i + 4); 33 | c += BitConverter.ToUInt32(data, i + 8); 34 | 35 | Mix(ref a, ref b, ref c); 36 | 37 | length -= 12; 38 | k += 12; 39 | } 40 | 41 | var l = data.Length - 12; 42 | 43 | a += BitConverter.ToUInt32(data, l); 44 | b += BitConverter.ToUInt32(data, l + 4); 45 | c += BitConverter.ToUInt32(data, l + 8); 46 | 47 | Final(ref a, ref b, ref c); 48 | 49 | return ((ulong)c << 32) | b; 50 | } 51 | 52 | void Mix(ref uint a, ref uint b, ref uint c) 53 | { 54 | a -= c; a ^= Rot(c, 4); c += b; 55 | b -= a; b ^= Rot(a, 6); a += c; 56 | c -= b; c ^= Rot(b, 8); b += a; 57 | a -= c; a ^= Rot(c, 16); c += b; 58 | b -= a; b ^= Rot(a, 19); a += c; 59 | c -= b; c ^= Rot(b, 4); b += a; 60 | } 61 | 62 | void Final(ref uint a, ref uint b, ref uint c) 63 | { 64 | c ^= b; c -= Rot(b, 14); 65 | a ^= c; a -= Rot(c, 11); 66 | b ^= a; b -= Rot(a, 25); 67 | c ^= b; c -= Rot(b, 16); 68 | a ^= c; a -= Rot(c, 4); 69 | b ^= a; b -= Rot(a, 14); 70 | c ^= b; c -= Rot(b, 24); 71 | } 72 | 73 | uint Rot(uint x, int k) 74 | { 75 | return (x << k) | (x >> (32 - k)); 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /WDBXEditor/Archives/CASC/Structures/BLTEChunk.cs: -------------------------------------------------------------------------------- 1 | namespace WDBXEditor.Archives.CASC.Structures 2 | { 3 | public struct BLTEChunk 4 | { 5 | public long CompressedSize { get; set; } 6 | public long UncompressedSize { get; set; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /WDBXEditor/Archives/CASC/Structures/BLTEEntry.cs: -------------------------------------------------------------------------------- 1 | namespace WDBXEditor.Archives.CASC.Structures 2 | { 3 | public class BLTEEntry 4 | { 5 | public BLTEChunk[] Chunks { get; set; } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /WDBXEditor/Archives/CASC/Structures/EncodingEntry.cs: -------------------------------------------------------------------------------- 1 | namespace WDBXEditor.Archives.CASC.Structures 2 | { 3 | public struct EncodingEntry 4 | { 5 | public byte[][] Keys { get; set; } 6 | public uint Size { get; set; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /WDBXEditor/Archives/CASC/Structures/IndexEntry.cs: -------------------------------------------------------------------------------- 1 | namespace WDBXEditor.Archives.CASC.Structures 2 | { 3 | public struct IndexEntry 4 | { 5 | public ushort Index { get; set; } 6 | public uint Offset { get; set; } 7 | public uint Size { get; set; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /WDBXEditor/Archives/CASC/Structures/RootEntry.cs: -------------------------------------------------------------------------------- 1 | using WDBXEditor.Archives.CASC.Constants; 2 | 3 | namespace WDBXEditor.Archives.CASC.Structures 4 | { 5 | public struct RootEntry 6 | { 7 | public byte[] MD5 { get; set; } 8 | public ulong Hash { get; set; } 9 | public Locales Locales { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /WDBXEditor/Archives/MPQ/MpqArchiveCompactingEventArgs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace WDBXEditor.Archives.MPQ 7 | { 8 | public delegate void MpqArchiveCompactingEventHandler(MpqArchive sender, MpqArchiveCompactingEventArgs e); 9 | 10 | public class MpqArchiveCompactingEventArgs : EventArgs 11 | { 12 | internal MpqArchiveCompactingEventArgs(uint dwWorkType, ulong processed, ulong total) 13 | { 14 | unchecked 15 | { 16 | WorkType = (MpqCompactingWorkType)dwWorkType; 17 | BytesProcessed = (long)processed; 18 | TotalBytes = (long)total; 19 | } 20 | } 21 | 22 | public MpqCompactingWorkType WorkType 23 | { 24 | get; 25 | private set; 26 | } 27 | 28 | public long BytesProcessed 29 | { 30 | get; 31 | private set; 32 | } 33 | 34 | public long TotalBytes 35 | { 36 | get; 37 | private set; 38 | } 39 | } 40 | 41 | public enum MpqCompactingWorkType 42 | { 43 | CheckingFiles = 1, 44 | CheckingHashTable = 2, 45 | CopyingNonMpqData = 3, 46 | CompactingFiles = 4, 47 | ClosingArchive = 5, 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /WDBXEditor/Archives/MPQ/MpqFileStream.cs: -------------------------------------------------------------------------------- 1 | using WDBXEditor.Archives.MPQ.Native; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.ComponentModel; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading; 9 | 10 | namespace WDBXEditor.Archives.MPQ 11 | { 12 | public class MpqFileStream : Stream 13 | { 14 | private MpqFileSafeHandle _handle; 15 | private FileAccess _accessType; 16 | private MpqArchive _owner; 17 | 18 | internal MpqFileStream(MpqFileSafeHandle handle, FileAccess accessType, MpqArchive owner) 19 | { 20 | _handle = handle; 21 | _accessType = accessType; 22 | _owner = owner; 23 | } 24 | 25 | private void VerifyHandle() 26 | { 27 | if (_handle == null || _handle.IsInvalid || _handle.IsClosed) 28 | throw new ObjectDisposedException("MpqFileStream"); 29 | } 30 | 31 | public override bool CanRead 32 | { 33 | get { VerifyHandle(); return true; } 34 | } 35 | 36 | public override bool CanSeek 37 | { 38 | get { VerifyHandle(); return true; } 39 | } 40 | 41 | public override bool CanWrite 42 | { 43 | get { VerifyHandle(); return _accessType != FileAccess.Read; } 44 | } 45 | 46 | public override void Flush() 47 | { 48 | VerifyHandle(); 49 | 50 | _owner.Flush(); 51 | } 52 | 53 | public override long Length 54 | { 55 | get 56 | { 57 | VerifyHandle(); 58 | 59 | uint high = 0; 60 | uint low = NativeMethods.SFileGetFileSize(_handle, ref high); 61 | 62 | ulong val = (high << 32) | low; 63 | return unchecked((long)val); 64 | } 65 | } 66 | 67 | public override long Position 68 | { 69 | get 70 | { 71 | VerifyHandle(); 72 | 73 | return NativeMethods.SFileGetFilePointer(_handle); 74 | } 75 | set 76 | { 77 | Seek(value, SeekOrigin.Begin); 78 | } 79 | } 80 | 81 | public override unsafe int Read(byte[] buffer, int offset, int count) 82 | { 83 | if (buffer == null) 84 | throw new ArgumentNullException("buffer"); 85 | if (offset > buffer.Length || (offset + count) > buffer.Length) 86 | throw new ArgumentException(); 87 | if (count < 0) 88 | throw new ArgumentOutOfRangeException("count"); 89 | 90 | VerifyHandle(); 91 | 92 | bool success; 93 | uint read; 94 | fixed (byte* pb = &buffer[offset]) 95 | { 96 | NativeOverlapped overlapped = default(NativeOverlapped); 97 | success = NativeMethods.SFileReadFile(_handle, new IntPtr(pb), unchecked((uint)count), out read, ref overlapped); 98 | } 99 | 100 | if (!success) 101 | throw new Exception("Unable to read file"); 102 | 103 | return unchecked((int)read); 104 | } 105 | 106 | public override long Seek(long offset, SeekOrigin origin) 107 | { 108 | VerifyHandle(); 109 | 110 | uint low, high; 111 | low = unchecked((uint)(offset & 0xffffffffu)); 112 | high = unchecked((uint)(offset >> 32)); 113 | return NativeMethods.SFileSetFilePointer(_handle, low, ref high, (uint)origin); 114 | } 115 | 116 | public override void SetLength(long value) 117 | { 118 | throw new NotSupportedException(); 119 | } 120 | 121 | public override unsafe void Write(byte[] buffer, int offset, int count) 122 | { 123 | VerifyHandle(); 124 | 125 | if (buffer == null) 126 | throw new ArgumentNullException("buffer"); 127 | if (offset > buffer.Length || (offset + count) > buffer.Length) 128 | throw new ArgumentException(); 129 | if (count < 0) 130 | throw new ArgumentOutOfRangeException("count"); 131 | 132 | VerifyHandle(); 133 | 134 | bool success; 135 | fixed (byte* pb = &buffer[offset]) 136 | { 137 | success = NativeMethods.SFileWriteFile(_handle, new IntPtr(pb), unchecked((uint)count), 0u); 138 | } 139 | 140 | if (!success) 141 | throw new Win32Exception(); 142 | } 143 | 144 | protected override void Dispose(bool disposing) 145 | { 146 | base.Dispose(disposing); 147 | 148 | if (disposing) 149 | { 150 | if (_handle != null && !_handle.IsInvalid) 151 | { 152 | _handle.Close(); 153 | _handle = null; 154 | } 155 | 156 | if (_owner != null) 157 | { 158 | _owner.RemoveOwnedFile(this); 159 | _owner = null; 160 | } 161 | } 162 | } 163 | 164 | public int ChecksumCrc32 165 | { 166 | get 167 | { 168 | throw new NotImplementedException(); 169 | } 170 | } 171 | 172 | public byte[] GetMd5Hash() 173 | { 174 | throw new NotImplementedException(); 175 | } 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /WDBXEditor/Archives/MPQ/Native/Callbacks.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Runtime.InteropServices; 5 | using System.Text; 6 | 7 | namespace WDBXEditor.Archives.MPQ.Native 8 | { 9 | [UnmanagedFunctionPointer(CallingConvention.Winapi)] 10 | internal delegate void SFILE_DOWNLOAD_CALLBACK(IntPtr pvUserData, ulong byteOffset, uint dwTotalBytes); 11 | 12 | [UnmanagedFunctionPointer(CallingConvention.Winapi)] 13 | internal delegate void SFILE_COMPACT_CALLBACK(IntPtr pvUserData, uint dwWorkType, ulong bytesProcessed, ulong totalBytes); 14 | 15 | [UnmanagedFunctionPointer(CallingConvention.Winapi)] 16 | internal delegate void SFILE_ADDFILE_CALLBACK(IntPtr pvUserData, uint dwBytesWritte, uint dwTotalBytes, bool bFinalCall); 17 | } 18 | -------------------------------------------------------------------------------- /WDBXEditor/Archives/MPQ/Native/MpqArchiveSafeHandle.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Win32.SafeHandles; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Runtime.InteropServices; 6 | using System.Text; 7 | 8 | namespace WDBXEditor.Archives.MPQ.Native 9 | { 10 | internal sealed class MpqArchiveSafeHandle : SafeHandleZeroOrMinusOneIsInvalid 11 | { 12 | public MpqArchiveSafeHandle(IntPtr handle) 13 | : base(true) 14 | { 15 | this.SetHandle(handle); 16 | } 17 | 18 | public MpqArchiveSafeHandle() 19 | : base(true) { } 20 | 21 | protected override bool ReleaseHandle() 22 | { 23 | return NativeMethods.SFileCloseArchive(this.handle); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /WDBXEditor/Archives/MPQ/Native/MpqFileSafeHandle.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Win32.SafeHandles; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace WDBXEditor.Archives.MPQ.Native 8 | { 9 | internal sealed class MpqFileSafeHandle : SafeHandleZeroOrMinusOneIsInvalid 10 | { 11 | public MpqFileSafeHandle(IntPtr handle) 12 | : base(true) 13 | { 14 | this.SetHandle(handle); 15 | } 16 | 17 | public MpqFileSafeHandle() 18 | : base(true) 19 | { 20 | } 21 | 22 | protected override bool ReleaseHandle() 23 | { 24 | return NativeMethods.SFileCloseFile(this.handle); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /WDBXEditor/Archives/MPQ/Native/SFileInfoClass.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace WDBXEditor.Archives.MPQ.Native 7 | { 8 | internal enum SFileInfoClass 9 | { 10 | // Info classes for archives 11 | SFileMpqFileName, // Name of the archive file (TCHAR []) 12 | SFileMpqStreamBitmap, // Array of bits, each bit means availability of one block (BYTE []) 13 | SFileMpqUserDataOffset, // Offset of the user data header (ULONGLONG) 14 | SFileMpqUserDataHeader, // Raw (unfixed) user data header (TMPQUserData) 15 | SFileMpqUserData, // MPQ USer data, without the header (BYTE []) 16 | SFileMpqHeaderOffset, // Offset of the MPQ header (ULONGLONG) 17 | SFileMpqHeaderSize, // Fixed size of the MPQ header 18 | SFileMpqHeader, // Raw (unfixed) archive header (TMPQHeader) 19 | SFileMpqHetTableOffset, // Offset of the HET table, relative to MPQ header (ULONGLONG) 20 | SFileMpqHetTableSize, // Compressed size of the HET table (ULONGLONG) 21 | SFileMpqHetHeader, // HET table header (TMPQHetHeader) 22 | SFileMpqHetTable, // HET table as pointer. Must be freed using SFileFreeFileInfo 23 | SFileMpqBetTableOffset, // Offset of the BET table, relative to MPQ header (ULONGLONG) 24 | SFileMpqBetTableSize, // Compressed size of the BET table (ULONGLONG) 25 | SFileMpqBetHeader, // BET table header, followed by the flags (TMPQBetHeader + DWORD[]) 26 | SFileMpqBetTable, // BET table as pointer. Must be freed using SFileFreeFileInfo 27 | SFileMpqHashTableOffset, // Hash table offset, relative to MPQ header (ULONGLONG) 28 | SFileMpqHashTableSize64, // Compressed size of the hash table (ULONGLONG) 29 | SFileMpqHashTableSize, // Size of the hash table, in entries (DWORD) 30 | SFileMpqHashTable, // Raw (unfixed) hash table (TMPQBlock []) 31 | SFileMpqBlockTableOffset, // Block table offset, relative to MPQ header (ULONGLONG) 32 | SFileMpqBlockTableSize64, // Compressed size of the block table (ULONGLONG) 33 | SFileMpqBlockTableSize, // Size of the block table, in entries (DWORD) 34 | SFileMpqBlockTable, // Raw (unfixed) block table (TMPQBlock []) 35 | SFileMpqHiBlockTableOffset, // Hi-block table offset, relative to MPQ header (ULONGLONG) 36 | SFileMpqHiBlockTableSize64, // Compressed size of the hi-block table (ULONGLONG) 37 | SFileMpqHiBlockTable, // The hi-block table (USHORT []) 38 | SFileMpqSignatures, // Signatures present in the MPQ (DWORD) 39 | SFileMpqStrongSignatureOffset, // Byte offset of the strong signature, relative to begin of the file (ULONGLONG) 40 | SFileMpqStrongSignatureSize, // Size of the strong signature (DWORD) 41 | SFileMpqStrongSignature, // The strong signature (BYTE []) 42 | SFileMpqArchiveSize64, // Archive size from the header (ULONGLONG) 43 | SFileMpqArchiveSize, // Archive size from the header (DWORD) 44 | SFileMpqMaxFileCount, // Max number of files in the archive (DWORD) 45 | SFileMpqFileTableSize, // Number of entries in the file table (DWORD) 46 | SFileMpqSectorSize, // Sector size (DWORD) 47 | SFileMpqNumberOfFiles, // Number of files (DWORD) 48 | SFileMpqRawChunkSize, // Size of the raw data chunk for MD5 49 | SFileMpqStreamFlags, // Stream flags (DWORD) 50 | SFileMpqIsReadOnly, // Nonzero if the MPQ is read only (DWORD) 51 | 52 | // Info classes for files 53 | SFileInfoPatchChain, // Chain of patches where the file is (TCHAR []) 54 | SFileInfoFileEntry, // The file entry for the file (TFileEntry) 55 | SFileInfoHashEntry, // Hash table entry for the file (TMPQHash) 56 | SFileInfoHashIndex, // Index of the hash table entry (DWORD) 57 | SFileInfoNameHash1, // The first name hash in the hash table (DWORD) 58 | SFileInfoNameHash2, // The second name hash in the hash table (DWORD) 59 | SFileInfoNameHash3, // 64-bit file name hash for the HET/BET tables (ULONGLONG) 60 | SFileInfoLocale, // File locale (DWORD) 61 | SFileInfoFileIndex, // Block index (DWORD) 62 | SFileInfoByteOffset, // File position in the archive (ULONGLONG) 63 | SFileInfoFileTime, // File time (ULONGLONG) 64 | SFileInfoFileSize, // Size of the file (DWORD) 65 | SFileInfoCompressedSize, // Compressed file size (DWORD) 66 | SFileInfoFlags, // File flags from (DWORD) 67 | SFileInfoEncryptionKey, // File encryption key 68 | SFileInfoEncryptionKeyRaw, // Unfixed value of the file key 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /WDBXEditor/Archives/MPQ/Native/SFileOpenArchiveFlags.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace WDBXEditor.Archives.MPQ.Native 7 | { 8 | [Flags] 9 | internal enum SFileOpenArchiveFlags : uint 10 | { 11 | None = 0, 12 | TypeIsFile = None, 13 | TypeIsMemoryMapped = 1, 14 | TypeIsHttp = 2, 15 | 16 | AccessReadOnly = 0x100, 17 | AccessReadWriteShare = 0x200, 18 | AccessUseBitmap = 0x400, 19 | 20 | DontOpenListfile = 0x10000, 21 | DontOpenAttributes = 0x20000, 22 | DontSearchHeader = 0x40000, 23 | ForceVersion1 = 0x80000, 24 | CheckSectorCRC = 0x100000, 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /WDBXEditor/Archives/MPQ/Native/Win32Methods.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Diagnostics; 5 | using System.IO.MemoryMappedFiles; 6 | using System.Linq; 7 | using System.Runtime.InteropServices; 8 | using System.Text; 9 | 10 | namespace WDBXEditor.Archives.MPQ.Native 11 | { 12 | internal static class Win32Methods 13 | { 14 | [DllImport("kernel32", ExactSpelling = false, SetLastError = true)] 15 | public static extern uint GetMappedFileName( 16 | IntPtr hProcess, 17 | IntPtr fileHandle, 18 | IntPtr lpFilename, 19 | uint nSize 20 | ); 21 | 22 | [DllImport("kernel32", ExactSpelling = false, SetLastError = true)] 23 | public static extern uint GetFinalPathNameByHandle( 24 | IntPtr hFile, 25 | IntPtr lpszFilePath, 26 | uint cchFilePath, 27 | uint dwFlags 28 | ); 29 | 30 | public static string GetFileNameOfMemoryMappedFile(MemoryMappedFile file) 31 | { 32 | const uint size = 522; 33 | IntPtr path = Marshal.AllocCoTaskMem(unchecked((int)size)); // MAX_PATH + 1 char 34 | 35 | string result = null; 36 | try 37 | { 38 | // constant 0x2 = VOLUME_NAME_NT 39 | uint test = GetFinalPathNameByHandle(file.SafeMemoryMappedFileHandle.DangerousGetHandle(), path, size, 0x2); 40 | if (test != 0) 41 | throw new Win32Exception(); 42 | 43 | result = Marshal.PtrToStringAuto(path); 44 | } 45 | catch 46 | { 47 | uint test = GetMappedFileName(Process.GetCurrentProcess().Handle, file.SafeMemoryMappedFileHandle.DangerousGetHandle(), path, size); 48 | if (test != 0) 49 | throw new Win32Exception(); 50 | 51 | result = Marshal.PtrToStringAuto(path); 52 | } 53 | 54 | return result; 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /WDBXEditor/Common/AutoProgressBar.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | using System.Windows.Forms; 9 | 10 | namespace WDBXEditor.Common 11 | { 12 | class AutoProgressBar : ProgressBar 13 | { 14 | private BackgroundWorker bgw = new BackgroundWorker(); 15 | 16 | public void Start(int increment = 3) 17 | { 18 | if (bgw.IsBusy) return; 19 | 20 | this.Style = ProgressBarStyle.Continuous; 21 | this.Value = 0; 22 | bgw.DoWork += new DoWorkEventHandler(bgw_DoWork); 23 | bgw.ProgressChanged += new ProgressChangedEventHandler(bgw_ProgressChanged); 24 | bgw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgw_RunWorkerCompleted); 25 | bgw.WorkerReportsProgress = true; 26 | bgw.WorkerSupportsCancellation = true; 27 | bgw.RunWorkerAsync(increment); 28 | } 29 | 30 | void bgw_DoWork(object sender, DoWorkEventArgs e) 31 | { 32 | int inc = (int)e.Argument; 33 | int i = 0; 34 | 35 | while (!bgw.CancellationPending) 36 | { 37 | System.Threading.Thread.Sleep(250); 38 | int percent = i; 39 | 40 | if (percent > 100) 41 | { 42 | percent = 100; 43 | i = 0; 44 | } 45 | else 46 | i += inc; 47 | 48 | bgw.ReportProgress(percent); 49 | } 50 | } 51 | 52 | void bgw_ProgressChanged(object sender, ProgressChangedEventArgs e) 53 | { 54 | if (!bgw.CancellationPending) 55 | this.Invoke((MethodInvoker)delegate { Value = e.ProgressPercentage; }); 56 | } 57 | 58 | void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 59 | { 60 | Task.Run(() => ClearValue()); 61 | } 62 | 63 | public void Stop(bool clear = true) 64 | { 65 | if (bgw.IsBusy) 66 | bgw.CancelAsync(); 67 | 68 | if (clear) 69 | Task.Run(() => ClearValue()); 70 | } 71 | 72 | private async Task ClearValue() 73 | { 74 | await Task.Factory.StartNew(() => 75 | { 76 | while (bgw.CancellationPending || this.Value != 0) 77 | { 78 | this.Invoke((MethodInvoker)delegate { this.Value = 0; }); 79 | Task.Delay(50).Wait(); 80 | } 81 | }); 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /WDBXEditor/Common/BufferedListBox.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Forms; 2 | 3 | namespace WDBXEditor.Common 4 | { 5 | class BufferedListBox : ListBox 6 | { 7 | public BufferedListBox() 8 | { 9 | this.DoubleBuffered = true; 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /WDBXEditor/Common/DropdownCheckList.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace WDBXEditor.Common 2 | { 3 | partial class DropdownCheckList 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Component Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.components = new System.ComponentModel.Container(); 32 | this.lbItems = new System.Windows.Forms.CheckedListBox(); 33 | this.cbBox = new System.Windows.Forms.ComboBox(); 34 | this.toolTip1 = new System.Windows.Forms.ToolTip(this.components); 35 | this.btnEmpty = new System.Windows.Forms.Button(); 36 | this.btnReset = new System.Windows.Forms.Button(); 37 | this.SuspendLayout(); 38 | // 39 | // lbItems 40 | // 41 | this.lbItems.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 42 | | System.Windows.Forms.AnchorStyles.Right))); 43 | this.lbItems.CheckOnClick = true; 44 | this.lbItems.FormattingEnabled = true; 45 | this.lbItems.Location = new System.Drawing.Point(0, 21); 46 | this.lbItems.Name = "lbItems"; 47 | this.lbItems.Size = new System.Drawing.Size(272, 94); 48 | this.lbItems.TabIndex = 1; 49 | this.lbItems.Visible = false; 50 | this.lbItems.ItemCheck += new System.Windows.Forms.ItemCheckEventHandler(this.lbItems_ItemCheck); 51 | // 52 | // cbBox 53 | // 54 | this.cbBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 55 | | System.Windows.Forms.AnchorStyles.Right))); 56 | this.cbBox.DrawMode = System.Windows.Forms.DrawMode.OwnerDrawFixed; 57 | this.cbBox.DropDownHeight = 1; 58 | this.cbBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; 59 | this.cbBox.DropDownWidth = 1; 60 | this.cbBox.FormattingEnabled = true; 61 | this.cbBox.IntegralHeight = false; 62 | this.cbBox.Items.AddRange(new object[] { 63 | "[All]"}); 64 | this.cbBox.Location = new System.Drawing.Point(0, 0); 65 | this.cbBox.Name = "cbBox"; 66 | this.cbBox.Size = new System.Drawing.Size(214, 21); 67 | this.cbBox.TabIndex = 0; 68 | this.cbBox.DrawItem += new System.Windows.Forms.DrawItemEventHandler(this.cbBox_DrawItem); 69 | this.cbBox.DropDown += new System.EventHandler(this.cbBox_DropDown); 70 | this.cbBox.DropDownClosed += new System.EventHandler(this.cbBox_DropDownClosed); 71 | // 72 | // btnEmpty 73 | // 74 | this.btnEmpty.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); 75 | this.btnEmpty.Image = global::WDBXEditor.Properties.Resources.hide; 76 | this.btnEmpty.Location = new System.Drawing.Point(217, -1); 77 | this.btnEmpty.Margin = new System.Windows.Forms.Padding(0); 78 | this.btnEmpty.Name = "btnEmpty"; 79 | this.btnEmpty.Size = new System.Drawing.Size(26, 23); 80 | this.btnEmpty.TabIndex = 3; 81 | this.toolTip1.SetToolTip(this.btnEmpty, "Hide Empty"); 82 | this.btnEmpty.UseVisualStyleBackColor = true; 83 | // 84 | // btnReset 85 | // 86 | this.btnReset.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); 87 | this.btnReset.Image = global::WDBXEditor.Properties.Resources.close; 88 | this.btnReset.Location = new System.Drawing.Point(246, -1); 89 | this.btnReset.Margin = new System.Windows.Forms.Padding(0); 90 | this.btnReset.Name = "btnReset"; 91 | this.btnReset.Size = new System.Drawing.Size(26, 23); 92 | this.btnReset.TabIndex = 2; 93 | this.toolTip1.SetToolTip(this.btnReset, "Reset"); 94 | this.btnReset.UseVisualStyleBackColor = true; 95 | this.btnReset.Click += new System.EventHandler(this.btnReset_Click); 96 | // 97 | // DropdownCheckList 98 | // 99 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 100 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 101 | this.Controls.Add(this.btnEmpty); 102 | this.Controls.Add(this.btnReset); 103 | this.Controls.Add(this.lbItems); 104 | this.Controls.Add(this.cbBox); 105 | this.Name = "DropdownCheckList"; 106 | this.Size = new System.Drawing.Size(272, 115); 107 | this.EnabledChanged += new System.EventHandler(this.DropdownCheckList_EnabledChanged); 108 | this.Leave += new System.EventHandler(this.DropdownCheckList_Leave); 109 | this.ResumeLayout(false); 110 | 111 | } 112 | 113 | #endregion 114 | private System.Windows.Forms.CheckedListBox lbItems; 115 | private System.Windows.Forms.ComboBox cbBox; 116 | private System.Windows.Forms.Button btnReset; 117 | private System.Windows.Forms.ToolTip toolTip1; 118 | private System.Windows.Forms.Button btnEmpty; 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /WDBXEditor/Common/FloatUtil.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace WDBXEditor.Common 8 | { 9 | /// 10 | /// android-apktool 11 | /// 12 | public class FloatUtil 13 | { 14 | private readonly static int canonicalFloatNaN = FloatToRawIntBits(float.NaN); 15 | private readonly static int maxFloat = FloatToRawIntBits(float.MaxValue); 16 | private readonly static int minFloat = FloatToRawIntBits(float.MinValue); 17 | private readonly static int piFloat = FloatToRawIntBits((float)Math.PI); 18 | private readonly static int eFloat = FloatToRawIntBits((float)Math.E); 19 | private readonly static int piNegFloat = FloatToRawIntBits(-(float)Math.PI); 20 | private readonly static int eNegFloat = FloatToRawIntBits(-(float)Math.E); 21 | private readonly static int pInfinity = FloatToRawIntBits(float.PositiveInfinity); 22 | private readonly static int nInfinity = FloatToRawIntBits(float.NegativeInfinity); 23 | 24 | private static unsafe int FloatToRawIntBits(float f) => *((int*)&f); 25 | private static unsafe float IntBitsToFloat(int i) => *((float*)&i); 26 | 27 | public static bool IsLikelyFloat(int value, int minexp = -7, int maxexp = 6) 28 | { 29 | // unwanted common named float values 30 | if (value == canonicalFloatNaN || value == maxFloat || value == minFloat || value == pInfinity || value == nInfinity) 31 | { 32 | return false; 33 | } 34 | 35 | // wanted common named float values 36 | if (value == eFloat || value == piFloat || value == eNegFloat || value == piNegFloat) 37 | { 38 | return true; 39 | } 40 | 41 | // check for some named integer values 42 | if (value == int.MaxValue || value == int.MinValue) 43 | { 44 | return false; 45 | } 46 | 47 | // check for likely resource id 48 | int packageId = value >> 24; 49 | int resourceType = value >> 16 & 0xff; 50 | int resourceId = value & 0xffff; 51 | if ((packageId == 0x7f || packageId == 1) && resourceType < 0x1f && resourceId < 0xfff) 52 | { 53 | return false; 54 | } 55 | 56 | // a non-canonical NaN is more likely to be an integer 57 | float floatValue = IntBitsToFloat(value); 58 | if (float.IsNaN(floatValue)) 59 | { 60 | return false; 61 | } 62 | 63 | // exponent range check, range is taken from the Alpha client 64 | double exp = Math.Floor(Math.Log10(Math.Abs(floatValue))); 65 | if (exp <= minexp || exp >= maxexp) 66 | return false; 67 | 68 | // try to strip off any small imprecision near the end of the mantissa, remove 0 exponent 69 | string asInt = StripImprecision(string.Format("{0:0.00000000000000000000E0}", value)); 70 | string asFloat = StripImprecision(string.Format("{0:0.00000000000000000000E0}", floatValue)); 71 | 72 | return asFloat.TrimEnd('0').Length < asInt.Length; 73 | } 74 | 75 | private static string StripImprecision(string value) 76 | { 77 | int dp = value.IndexOf('.'); 78 | int exp = value.IndexOf("E"); 79 | int zeros = value.IndexOf("000"); 80 | int nines = value.IndexOf("999"); 81 | 82 | if (zeros > dp && zeros < exp) 83 | { 84 | value = value.Substring(0, zeros) + value.Substring(exp); 85 | } 86 | else if (nines > dp && nines < exp) 87 | { 88 | value = value.Substring(0, nines) + value.Substring(exp); 89 | } 90 | 91 | return value; 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /WDBXEditor/Common/FormHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows.Forms; 7 | using WDBXEditor.Storage; 8 | 9 | namespace WDBXEditor.Common 10 | { 11 | static class FormHandler 12 | { 13 | private static Main _Parent; 14 | private static Dictionary _Forms = new Dictionary(); 15 | 16 | static FormHandler() 17 | { 18 | _Parent = GetForm
(); 19 | } 20 | 21 | public static T Show(params object[] args) where T : Form, new() 22 | { 23 | var type = typeof(T); 24 | bool findreplace = typeof(T) == typeof(FindReplace); 25 | Form f = null; 26 | 27 | if (findreplace) //FindReplace argument check 28 | { 29 | if (args.Length == 0) 30 | throw new ArgumentException("FindReplace requires Screen Type argument."); 31 | if (args[0].GetType() != typeof(bool)) 32 | throw new ArgumentException("FindReplace argument should be a boolean."); 33 | } 34 | 35 | if (_Forms.TryGetValue(type, out f)) 36 | { 37 | f.BringToFront(); 38 | f.Activate(); 39 | } 40 | else 41 | { 42 | f = new T(); 43 | f.FormClosing += (s, e) => _Forms.Remove(s.GetType()); 44 | f.TopMost = true; 45 | f.Show(_Parent); 46 | 47 | _Forms.Add(type, f); 48 | } 49 | 50 | if (findreplace) 51 | ((FindReplace)f).SetScreenType((bool)args[0]); //Set FindReplace screen type 52 | 53 | return (T)f; 54 | } 55 | 56 | public static T GetForm() where T : Form 57 | { 58 | return Application.OpenForms.Cast
().FirstOrDefault(x => x.GetType() == typeof(T)) as T; 59 | } 60 | 61 | public static void Close() 62 | { 63 | var type = typeof(T); 64 | Form f = null; 65 | if (_Forms.TryGetValue(type, out f)) 66 | f?.Close(); 67 | } 68 | 69 | public static void Close() 70 | { 71 | foreach (var form in _Forms.Values) 72 | form?.Close(); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /WDBXEditor/Common/GithubReleaseModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace WDBXEditor.Common 5 | { 6 | public class GithubReleaseModel 7 | { 8 | public string url { get; set; } 9 | public string assets_url { get; set; } 10 | public string upload_url { get; set; } 11 | public string html_url { get; set; } 12 | public int id { get; set; } 13 | public string tag_name { get; set; } 14 | public string target_commitish { get; set; } 15 | public bool draft { get; set; } 16 | public object author { get; set; } // placeholder 17 | public bool prerelease { get; set; } 18 | public DateTime created_at { get; set; } 19 | public DateTime updated_at { get; set; } 20 | public IList assets { get; set; } 21 | public string tarball_url { get; set; } 22 | public string zipball_url { get; set; } 23 | public string body { get; set; } 24 | } 25 | 26 | public class GithubRealaseAssetsModel 27 | { 28 | public string url { get; set; } 29 | public int id { get; set; } 30 | public string name { get; set; } 31 | public object label { get; set; } 32 | public object uploader { get; set; } // placeholder 33 | public string content_type { get; set; } 34 | public string state { get; set; } 35 | public int size { get; set; } 36 | public int download_count { get; set; } 37 | public DateTime created_at { get; set; } 38 | public DateTime updated_at { get; set; } 39 | public string browser_download_url { get; set; } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /WDBXEditor/Common/ORowComparer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace WDBXEditor.Common 8 | { 9 | public class ORowComparer : IEqualityComparer 10 | { 11 | public bool Equals(ORow x, ORow y) 12 | { 13 | var xa = x.Array; 14 | var ya = y.Array; 15 | 16 | for (int i = 0; i < xa.Length; i++) 17 | if (!xa[i].Equals(ya[i])) 18 | return false; 19 | 20 | return true; 21 | } 22 | 23 | public int GetHashCode(ORow obj) 24 | { 25 | unchecked 26 | { 27 | var a = obj.Array; 28 | int hash = (int)2166136261; 29 | for (int i = 0; i < a.Length; i++) 30 | hash = (hash * 16777619) ^ a[i].GetHashCode(); 31 | return hash; 32 | } 33 | } 34 | } 35 | 36 | public class OArrayComparer : IEqualityComparer 37 | { 38 | public bool Equals(object[] x, object[] y) 39 | { 40 | for (int i = 0; i < x.Length; i++) 41 | if (!x[i].Equals(y[i])) 42 | return false; 43 | 44 | return true; 45 | } 46 | 47 | public int GetHashCode(object[] obj) 48 | { 49 | unchecked 50 | { 51 | int hash = (int)2166136261; 52 | for (int i = 0; i < obj.Length; i++) 53 | hash = (hash * 16777619) ^ obj[i].GetHashCode(); 54 | return hash; 55 | } 56 | } 57 | } 58 | 59 | public class ORow 60 | { 61 | public int Index; 62 | public object[] Array; 63 | 64 | public ORow(int index, object[] array) 65 | { 66 | Index = index; 67 | Array = array; 68 | } 69 | } 70 | 71 | 72 | } 73 | -------------------------------------------------------------------------------- /WDBXEditor/ConsoleHandler/ConsoleManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using WDBXEditor.Storage; 8 | 9 | namespace WDBXEditor.ConsoleHandler 10 | { 11 | public static class ConsoleManager 12 | { 13 | public static bool ConsoleMode { get; set; } = false; 14 | 15 | public static Dictionary CommandHandlers = new Dictionary(); 16 | public delegate void HandleCommand(string[] args); 17 | 18 | public static void ConsoleMain(string[] args) 19 | { 20 | Database.LoadDefinitions().Wait(); 21 | 22 | if (CommandHandlers.ContainsKey(args[0].ToLower())) 23 | InvokeHandler(args[0], args.Skip(1).ToArray()); 24 | } 25 | 26 | public static bool InvokeHandler(string command, params string[] args) 27 | { 28 | try 29 | { 30 | command = command.ToLower(); 31 | if (CommandHandlers.ContainsKey(command)) 32 | { 33 | CommandHandlers[command].Invoke(args); 34 | return true; 35 | } 36 | else 37 | return false; 38 | } 39 | catch (Exception ex) 40 | { 41 | Console.WriteLine(ex.Message); 42 | Console.WriteLine(""); 43 | return false; 44 | } 45 | } 46 | 47 | public static void LoadCommandDefinitions() 48 | { 49 | //Argument commands 50 | //DefineCommand("-console", ConsoleManager.LoadConsoleMode); 51 | DefineCommand("-export", ConsoleCommands.ExportArgCommand); 52 | DefineCommand("-sqldump", ConsoleCommands.SqlDumpArgCommand); 53 | DefineCommand("-extract", ConsoleCommands.ExtractCommand); 54 | DefineCommand("-sqlload", ConsoleCommands.SqlLoadArgCommand); 55 | } 56 | 57 | /// 58 | /// Converts args into keyvalue pair 59 | /// 60 | /// 61 | /// 62 | public static Dictionary ParseCommand(string[] args) 63 | { 64 | Dictionary keyvalues = new Dictionary(); 65 | for (int i = 0; i < args.Length; i++) 66 | { 67 | if (i == args.Length - 1) 68 | break; 69 | 70 | string key = args[i].ToLower(); 71 | string value = args[++i]; 72 | if (value[0] == '"' && value[value.Length - 1] == '"') 73 | value = value.Substring(1, value.Length - 2); 74 | 75 | keyvalues.Add(key, value); 76 | } 77 | 78 | return keyvalues; 79 | } 80 | 81 | private static void DefineCommand(string command, HandleCommand handler) 82 | { 83 | CommandHandlers[command.ToLower()] = handler; 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /WDBXEditor/Definitions/Offsets.json: -------------------------------------------------------------------------------- 1 | [{"Name":"1.12.1.5875 x86","UseBase":true,"ClientConnection":7607316,"ObjectManager":0,"FirstObjectOffset":172,"LocalGuidOffset":192,"NextObjectOffset":60,"MapID":4621696,"Pos_X":2488,"Pos_Y":2492,"Pos_Z":2496,"Guid":48},{"Name":"2.4.3.8606 x86","UseBase":false,"ClientConnection":13906712,"ObjectManager":8728,"FirstObjectOffset":172,"LocalGuidOffset":192,"NextObjectOffset":60,"MapID":14781876,"Pos_X":3056,"Pos_Y":3060,"Pos_Z":3064,"Guid":48},{"Name":"3.3.5.12340 x86","UseBase":false,"ClientConnection":13081824,"ObjectManager":11984,"FirstObjectOffset":172,"LocalGuidOffset":192,"NextObjectOffset":60,"MapID":11232188,"Pos_X":1944,"Pos_Y":1948,"Pos_Z":1952,"Guid":48}] -------------------------------------------------------------------------------- /WDBXEditor/Forms/ColourConverter.cs: -------------------------------------------------------------------------------- 1 | using ADGV; 2 | using System; 3 | using System.Drawing; 4 | using System.Windows.Forms; 5 | using WDBXEditor.Common; 6 | 7 | namespace WDBXEditor.Forms 8 | { 9 | public partial class ColourConverter : Form 10 | { 11 | private AdvancedDataGridView _data; 12 | private bool _closing = false; 13 | 14 | private Func ColourToInt = c => BitConverter.ToUInt32(new byte[] { c.B, c.G, c.R, 0 }, 0); 15 | private Func UIntToColor = i => 16 | { 17 | var bytes = BitConverter.GetBytes(i); 18 | return Color.FromArgb(0, bytes[2], bytes[1], bytes[0]); //Alpha always 0 19 | }; 20 | 21 | #region Colour Events 22 | public ColourConverter() 23 | { 24 | InitializeComponent(); 25 | colourWheelChanged(colourWheel, null); 26 | } 27 | 28 | private void ColourConverter_Load(object sender, EventArgs e) 29 | { 30 | _data = (AdvancedDataGridView)((Main)Owner).Controls.Find("advancedDataGridView", true)[0]; 31 | } 32 | 33 | private void colourWheelChanged(object sender, EventArgs e) 34 | { 35 | txtRed.Text = colourWheel.CurrentColour.R.ToString(); 36 | txtGreen.Text = colourWheel.CurrentColour.G.ToString(); 37 | txtBlue.Text = colourWheel.CurrentColour.B.ToString(); 38 | picColour.BackColor = colourWheel.CurrentColour; 39 | txtWoWVal.Text = ColourToInt(colourWheel.CurrentColour).ToString(); 40 | } 41 | 42 | private void txtWoWVal_KeyPress(object sender, KeyPressEventArgs e) 43 | { 44 | if (!char.IsDigit(e.KeyChar) && !char.IsControl(e.KeyChar)) 45 | { 46 | e.Handled = true; 47 | return; 48 | } 49 | } 50 | 51 | private void txtWoWVal_KeyUp(object sender, KeyEventArgs e) 52 | { 53 | ulong dmp; 54 | if (!ulong.TryParse(txtWoWVal.Text, out dmp)) 55 | txtWoWVal.Text = "0"; 56 | else if (dmp > uint.MaxValue) 57 | txtWoWVal.Text = uint.MaxValue.ToString(); 58 | 59 | colourWheel.CurrentColour = UIntToColor(Convert.ToUInt32(txtWoWVal.Text)); 60 | txtRed.Text = colourWheel.CurrentColour.R.ToString(); 61 | txtGreen.Text = colourWheel.CurrentColour.G.ToString(); 62 | txtBlue.Text = colourWheel.CurrentColour.B.ToString(); 63 | picColour.BackColor = colourWheel.CurrentColour; 64 | } 65 | 66 | private void txtColourKeyPress(object sender, KeyPressEventArgs e) 67 | { 68 | if (!char.IsDigit(e.KeyChar) && !char.IsControl(e.KeyChar)) 69 | { 70 | e.Handled = true; 71 | return; 72 | } 73 | } 74 | 75 | private void txtColourKeyUp(object sender, KeyEventArgs e) 76 | { 77 | ulong dmp; 78 | if (!ulong.TryParse(txtBlue.Text, out dmp)) //Check blue 79 | txtBlue.Text = "0"; 80 | else if (dmp > 255) 81 | txtBlue.Text = "255"; 82 | 83 | if (!ulong.TryParse(txtRed.Text, out dmp)) //Check red 84 | txtRed.Text = "0"; 85 | else if (dmp > 255) 86 | txtRed.Text = "255"; 87 | 88 | if (!ulong.TryParse(txtGreen.Text, out dmp)) //Check green 89 | txtGreen.Text = "0"; 90 | else if (dmp > 255) 91 | txtGreen.Text = "255"; 92 | 93 | colourWheel.CurrentColour = Color.FromArgb(0, Convert.ToInt32(txtRed.Text), Convert.ToInt32(txtGreen.Text), Convert.ToInt32(txtBlue.Text)); 94 | picColour.BackColor = colourWheel.CurrentColour; 95 | txtWoWVal.Text = ColourToInt(colourWheel.CurrentColour).ToString(); 96 | } 97 | #endregion 98 | 99 | #region Button Events 100 | private void btnGet_Click(object sender, EventArgs e) 101 | { 102 | ulong dmp; 103 | ulong.TryParse(_data.CurrentCell.Value.ToString(), out dmp); 104 | if (dmp > uint.MaxValue) 105 | dmp = uint.MaxValue; 106 | 107 | colourWheel.CurrentColour = UIntToColor((uint)dmp); 108 | colourWheelChanged(colourWheel, null); 109 | } 110 | 111 | private void betSet_Click(object sender, EventArgs e) 112 | { 113 | uint value = ColourToInt(colourWheel.CurrentColour); 114 | 115 | _data.BeginEdit(true); 116 | _data.CurrentCell.Value = value; 117 | _data.EndEdit(); 118 | } 119 | #endregion 120 | 121 | #region Form Events 122 | private void ColourConverter_Activated(object sender, EventArgs e) 123 | { 124 | if (_closing) return; 125 | this.Opacity = 1; 126 | } 127 | 128 | private void ColourConverter_Deactivate(object sender, EventArgs e) 129 | { 130 | if (_closing) return; 131 | this.Opacity = 0.75f; 132 | } 133 | 134 | private void ColourConverter_FormClosing(object sender, FormClosingEventArgs e) 135 | { 136 | _closing = true; 137 | } 138 | 139 | 140 | #endregion 141 | 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /WDBXEditor/Forms/ErrorReport.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace WDBXEditor.Forms 2 | { 3 | partial class ErrorReport 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ErrorReport)); 32 | this.label1 = new System.Windows.Forms.Label(); 33 | this.txtErrors = new System.Windows.Forms.RichTextBox(); 34 | this.btnOK = new System.Windows.Forms.Button(); 35 | this.SuspendLayout(); 36 | // 37 | // label1 38 | // 39 | this.label1.AutoSize = true; 40 | this.label1.Location = new System.Drawing.Point(12, 9); 41 | this.label1.Name = "label1"; 42 | this.label1.Size = new System.Drawing.Size(144, 13); 43 | this.label1.TabIndex = 0; 44 | this.label1.Text = "The following errors occured:"; 45 | // 46 | // txtErrors 47 | // 48 | this.txtErrors.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 49 | | System.Windows.Forms.AnchorStyles.Right))); 50 | this.txtErrors.Cursor = System.Windows.Forms.Cursors.IBeam; 51 | this.txtErrors.Location = new System.Drawing.Point(12, 25); 52 | this.txtErrors.Name = "txtErrors"; 53 | this.txtErrors.ReadOnly = true; 54 | this.txtErrors.Size = new System.Drawing.Size(437, 333); 55 | this.txtErrors.TabIndex = 1; 56 | this.txtErrors.Text = ""; 57 | // 58 | // btnOK 59 | // 60 | this.btnOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); 61 | this.btnOK.DialogResult = System.Windows.Forms.DialogResult.Cancel; 62 | this.btnOK.Location = new System.Drawing.Point(374, 364); 63 | this.btnOK.Name = "btnOK"; 64 | this.btnOK.Size = new System.Drawing.Size(75, 23); 65 | this.btnOK.TabIndex = 0; 66 | this.btnOK.Text = "Close"; 67 | this.btnOK.UseVisualStyleBackColor = true; 68 | // 69 | // ErrorReport 70 | // 71 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 72 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 73 | this.CancelButton = this.btnOK; 74 | this.ClientSize = new System.Drawing.Size(461, 390); 75 | this.Controls.Add(this.btnOK); 76 | this.Controls.Add(this.txtErrors); 77 | this.Controls.Add(this.label1); 78 | this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); 79 | this.MaximizeBox = false; 80 | this.MinimizeBox = false; 81 | this.Name = "ErrorReport"; 82 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; 83 | this.Text = "Error Report"; 84 | this.TopMost = true; 85 | this.Load += new System.EventHandler(this.ErrorReport_Load); 86 | this.ResumeLayout(false); 87 | this.PerformLayout(); 88 | 89 | } 90 | 91 | #endregion 92 | 93 | private System.Windows.Forms.Label label1; 94 | private System.Windows.Forms.RichTextBox txtErrors; 95 | private System.Windows.Forms.Button btnOK; 96 | } 97 | } -------------------------------------------------------------------------------- /WDBXEditor/Forms/ErrorReport.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows.Forms; 10 | 11 | namespace WDBXEditor.Forms 12 | { 13 | public partial class ErrorReport : Form 14 | { 15 | public string Message { get; set; } 16 | public IEnumerable Errors { get; set;} 17 | 18 | public ErrorReport() 19 | { 20 | InitializeComponent(); 21 | } 22 | 23 | public ErrorReport(IEnumerable Errors) 24 | { 25 | InitializeComponent(); 26 | this.Errors = Errors; 27 | } 28 | 29 | private void ErrorReport_Load(object sender, EventArgs e) 30 | { 31 | txtErrors.Clear(); 32 | txtErrors.SelectionBullet = true; 33 | txtErrors.SelectedText = string.Join("\n", Errors); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /WDBXEditor/Forms/FindReplace.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 | -------------------------------------------------------------------------------- /WDBXEditor/Forms/LoadCSV.cs: -------------------------------------------------------------------------------- 1 | using WDBXEditor.Storage; 2 | using System; 3 | using System.Windows.Forms; 4 | using static WDBXEditor.Common.Constants; 5 | using System.Threading.Tasks; 6 | 7 | namespace WDBXEditor 8 | { 9 | public partial class LoadCSV : Form 10 | { 11 | public DBEntry Entry { get; set; } 12 | public string ErrorMessage = string.Empty; 13 | 14 | private string filePath; 15 | 16 | public LoadCSV() 17 | { 18 | InitializeComponent(); 19 | } 20 | 21 | private void btnBrowse_Click(object sender, EventArgs e) 22 | { 23 | if (openFileDialog.ShowDialog() == DialogResult.OK) 24 | { 25 | btnLoad.Enabled = true; 26 | filePath = openFileDialog.FileName; 27 | txtFilePath.Text = filePath; 28 | openFileDialog.Dispose(); 29 | } 30 | } 31 | 32 | private void btnLoad_Click(object sender, EventArgs e) 33 | { 34 | ((Main)this.Owner).ProgressBarHandle(true, "Importing CSV..."); 35 | this.Enabled = false; 36 | bool header = chkHeader.Checked; 37 | 38 | ImportFlags flags = ImportFlags.None; 39 | if (rdoFixIds.Checked) 40 | flags |= ImportFlags.FixIds; 41 | if (rdoNewest.Checked) 42 | flags |= ImportFlags.TakeNewest; 43 | 44 | Task.Factory.StartNew(() => 45 | { 46 | UpdateMode mode = UpdateMode.Insert; 47 | if (radUpdate.Checked) 48 | mode = UpdateMode.Update; 49 | else if (radOverride.Checked) 50 | mode = UpdateMode.Replace; 51 | 52 | if (!Entry.ImportCSV(filePath, header, mode, out ErrorMessage, flags)) 53 | return DialogResult.Abort; 54 | else 55 | return DialogResult.OK; 56 | }) 57 | .ContinueWith(x => 58 | { 59 | this.Enabled = true; 60 | this.DialogResult = x.Result; 61 | this.Close(); 62 | 63 | }, TaskScheduler.FromCurrentSynchronizationContext()); 64 | 65 | } 66 | 67 | private void btnClose_Click(object sender, EventArgs e) 68 | { 69 | this.DialogResult = DialogResult.Cancel; 70 | this.Close(); 71 | } 72 | 73 | private void chkFixIds_CheckedChanged(object sender, EventArgs e) 74 | { 75 | if (rdoFixIds.Checked) 76 | rdoNewest.Checked = false; 77 | } 78 | 79 | private void chkNewest_CheckedChanged(object sender, EventArgs e) 80 | { 81 | if (rdoNewest.Checked) 82 | rdoFixIds.Checked = false; 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /WDBXEditor/Forms/LoadDefinition.cs: -------------------------------------------------------------------------------- 1 | using WDBXEditor.Storage; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Data; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Windows.Forms; 8 | using static WDBXEditor.Common.Constants; 9 | 10 | namespace WDBXEditor 11 | { 12 | public partial class LoadDefinition : Form 13 | { 14 | public IEnumerable Files { get; set; } 15 | 16 | public LoadDefinition() 17 | { 18 | InitializeComponent(); 19 | openFileDialog.InitialDirectory = DEFINITION_DIR; 20 | } 21 | 22 | private void LoadDefinition_Load(object sender, EventArgs e) 23 | { 24 | btnLoad.Enabled = false; 25 | LoadBuilds(); 26 | } 27 | 28 | public void UpdateFiles(IEnumerable files) 29 | { 30 | Files = Files.Concat(files); 31 | LoadBuilds(); 32 | } 33 | 34 | #region Button Events 35 | private void btnLoad_Click(object sender, EventArgs e) 36 | { 37 | int build = (int)lbDefinitions.SelectedValue; 38 | Database.BuildNumber = build; 39 | this.DialogResult = DialogResult.OK; 40 | this.Close(); 41 | } 42 | 43 | private void btnClose_Click(object sender, EventArgs e) 44 | { 45 | this.DialogResult = DialogResult.Cancel; 46 | this.Close(); 47 | } 48 | 49 | private void btnNewWindow_Click(object sender, EventArgs e) 50 | { 51 | if (InstanceManager.LoadNewInstance(Files)) 52 | { 53 | this.DialogResult = DialogResult.Cancel; 54 | this.Close(); 55 | } 56 | } 57 | #endregion 58 | 59 | #region Listbox 60 | private void lbDefinitions_SelectedValueChanged(object sender, EventArgs e) 61 | { 62 | btnLoad.Enabled = lbDefinitions.SelectedItems.Count > 0; 63 | } 64 | 65 | private void lbDefinitions_MouseDoubleClick(object sender, MouseEventArgs e) 66 | { 67 | int index = lbDefinitions.IndexFromPoint(e.Location); 68 | if (index != ListBox.NoMatches) 69 | { 70 | int build = (int)lbDefinitions.SelectedValue; 71 | Database.BuildNumber = build; 72 | this.DialogResult = DialogResult.OK; 73 | this.Close(); 74 | } 75 | } 76 | #endregion 77 | 78 | private void LoadBuilds(bool mostRecent = true) 79 | { 80 | if (Database.Definitions.Tables.Count == 0) 81 | { 82 | MessageBox.Show("No defintions found."); 83 | return; 84 | } 85 | 86 | if (Files?.Count() == 0) 87 | { 88 | SetFileText(); 89 | lbDefinitions.DataSource = null; 90 | MessageBox.Show("No files to load."); 91 | return; 92 | } 93 | 94 | //Get compatible builds only 95 | bool db2 = Files.Any(x => Path.GetExtension(x).IndexOf("db2", IGNORECASE) >= 0) || Files.Any(x => Path.GetExtension(x).IndexOf("adb", IGNORECASE) >= 0); 96 | 97 | var files = Files.Select(x => Path.GetFileNameWithoutExtension(x).ToLower()); 98 | var datasource = Database.Definitions.Tables 99 | .Where(x => files.Contains(x.Name.ToLower())) 100 | .Select(x => new { Key = x.Build, Value = x.BuildText }) 101 | .Distinct() 102 | .Where(x => db2 ? x.Key > (int)ExpansionFinalBuild.WotLK : true); // filter out non DB2/ADB clients 103 | 104 | // filter to the latest build for each version 105 | if (mostRecent) 106 | datasource = datasource.GroupBy(x => x.Value.Split('(').First()).Select(x => x.Aggregate((a, b) => a.Key > b.Key ? a : b)); 107 | 108 | // order 109 | datasource = datasource.OrderBy(x => x.Key); 110 | 111 | 112 | lbDefinitions.BeginUpdate(); 113 | 114 | if (datasource.Count() == 0) 115 | { 116 | lbDefinitions.DataSource = null; 117 | } 118 | else 119 | { 120 | lbDefinitions.DataSource = new BindingSource(datasource, null); 121 | lbDefinitions.DisplayMember = "Value"; 122 | lbDefinitions.ValueMember = "Key"; 123 | } 124 | 125 | SetFileText(); 126 | lbDefinitions.EndUpdate(); 127 | } 128 | 129 | private void SetFileText() 130 | { 131 | lblFiles.Text = Files.Count() == 1 ? "1 file" : Files.Count() + " files"; 132 | } 133 | 134 | private void chkBuildFilter_CheckedChanged(object sender, EventArgs e) 135 | { 136 | LoadBuilds(!chkBuildFilter.Checked); 137 | } 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /WDBXEditor/Forms/LoadHotfix.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace WDBXEditor.Forms 2 | { 3 | partial class LoadHotfix 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.label3 = new System.Windows.Forms.Label(); 32 | this.btnLoad = new System.Windows.Forms.Button(); 33 | this.btnClose = new System.Windows.Forms.Button(); 34 | this.lbDefinitions = new WDBXEditor.Common.BufferedListBox(); 35 | this.SuspendLayout(); 36 | // 37 | // label3 38 | // 39 | this.label3.AutoSize = true; 40 | this.label3.Location = new System.Drawing.Point(9, 9); 41 | this.label3.Name = "label3"; 42 | this.label3.Size = new System.Drawing.Size(161, 13); 43 | this.label3.TabIndex = 17; 44 | this.label3.Text = "Select which hotfix entry to read:"; 45 | // 46 | // btnLoad 47 | // 48 | this.btnLoad.Location = new System.Drawing.Point(116, 233); 49 | this.btnLoad.Name = "btnLoad"; 50 | this.btnLoad.Size = new System.Drawing.Size(75, 23); 51 | this.btnLoad.TabIndex = 15; 52 | this.btnLoad.Text = "Load"; 53 | this.btnLoad.UseVisualStyleBackColor = true; 54 | this.btnLoad.Click += new System.EventHandler(this.btnLoad_Click); 55 | // 56 | // btnClose 57 | // 58 | this.btnClose.Location = new System.Drawing.Point(197, 233); 59 | this.btnClose.Name = "btnClose"; 60 | this.btnClose.Size = new System.Drawing.Size(75, 23); 61 | this.btnClose.TabIndex = 16; 62 | this.btnClose.Text = "Close"; 63 | this.btnClose.UseVisualStyleBackColor = true; 64 | this.btnClose.Click += new System.EventHandler(this.btnClose_Click); 65 | // 66 | // lbDefinitions 67 | // 68 | this.lbDefinitions.FormattingEnabled = true; 69 | this.lbDefinitions.Location = new System.Drawing.Point(12, 28); 70 | this.lbDefinitions.Name = "lbDefinitions"; 71 | this.lbDefinitions.Size = new System.Drawing.Size(260, 199); 72 | this.lbDefinitions.TabIndex = 14; 73 | // 74 | // LoadHotfix 75 | // 76 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 77 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 78 | this.ClientSize = new System.Drawing.Size(284, 261); 79 | this.Controls.Add(this.label3); 80 | this.Controls.Add(this.btnLoad); 81 | this.Controls.Add(this.btnClose); 82 | this.Controls.Add(this.lbDefinitions); 83 | this.MaximizeBox = false; 84 | this.MaximumSize = new System.Drawing.Size(300, 300); 85 | this.MinimizeBox = false; 86 | this.MinimumSize = new System.Drawing.Size(300, 300); 87 | this.Name = "LoadHotfix"; 88 | this.ShowIcon = false; 89 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; 90 | this.Text = "Load Hotfix"; 91 | this.Load += new System.EventHandler(this.LoadHotfix_Load); 92 | this.ResumeLayout(false); 93 | this.PerformLayout(); 94 | 95 | } 96 | 97 | #endregion 98 | private System.Windows.Forms.Label label3; 99 | private System.Windows.Forms.Button btnLoad; 100 | private System.Windows.Forms.Button btnClose; 101 | private Common.BufferedListBox lbDefinitions; 102 | } 103 | } -------------------------------------------------------------------------------- /WDBXEditor/Forms/LoadHotfix.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows.Forms; 10 | using WDBXEditor.Reader.FileTypes; 11 | using WDBXEditor.Storage; 12 | 13 | namespace WDBXEditor.Forms 14 | { 15 | public partial class LoadHotfix : Form 16 | { 17 | private DBEntry Hotfix; 18 | 19 | public LoadHotfix() 20 | { 21 | InitializeComponent(); 22 | } 23 | 24 | private void LoadHotfix_Load(object sender, EventArgs e) 25 | { 26 | Hotfix = Database.Entries.FirstOrDefault(x => x.Header.IsTypeOf()); //Get our hotfix entry 27 | 28 | //Get all loaded entries that are contained in our hotfix entry 29 | var datasource = Database.Entries.Where(x => ((HTFX)Hotfix.Header).HasEntry(x.Header)) 30 | .Select(x => new 31 | { 32 | Key = x, 33 | Value = $"{x.FileName} ({x.TableStructure.Build})" 34 | }); 35 | 36 | if (datasource.Count() == 0) 37 | { 38 | lbDefinitions.DataSource = null; 39 | } 40 | else 41 | { 42 | lbDefinitions.DataSource = new BindingSource(datasource, null); 43 | lbDefinitions.DisplayMember = "Value"; 44 | lbDefinitions.ValueMember = "Key"; 45 | } 46 | } 47 | 48 | private void btnLoad_Click(object sender, EventArgs e) 49 | { 50 | var counterpart = (lbDefinitions.SelectedValue as DBEntry)?.Header; 51 | (Hotfix.Header as HTFX).Read(counterpart, Hotfix); 52 | 53 | this.DialogResult = DialogResult.OK; 54 | this.Close(); 55 | } 56 | 57 | private void btnClose_Click(object sender, EventArgs e) 58 | { 59 | this.DialogResult = DialogResult.Cancel; 60 | this.Close(); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /WDBXEditor/Forms/LoadHotfix.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 | -------------------------------------------------------------------------------- /WDBXEditor/Forms/TextEditor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows.Forms; 10 | using static WDBXEditor.Common.Constants; 11 | 12 | namespace WDBXEditor.Forms 13 | { 14 | public partial class TextEditor : Form 15 | { 16 | public string CellValue 17 | { 18 | get { return txtText.Text.Replace(Environment.NewLine,"\n"); } 19 | set 20 | { 21 | txtText.Text = value.Replace("\r\n","\n").Replace("\n",Environment.NewLine); 22 | txtText.SelectionStart = 0; 23 | txtText.SelectionLength = 0; 24 | } 25 | } 26 | 27 | public TextEditor() 28 | { 29 | InitializeComponent(); 30 | } 31 | 32 | private void btnClose_Click(object sender, EventArgs e) 33 | { 34 | this.Close(); 35 | } 36 | 37 | private void btnSave_Click(object sender, EventArgs e) 38 | { 39 | this.DialogResult = DialogResult.OK; 40 | this.Close(); 41 | } 42 | 43 | private void btnFind_Click(object sender, EventArgs e) 44 | { 45 | if (string.IsNullOrEmpty(txtFilter.Text)) 46 | return; 47 | 48 | int filterlen = txtFilter.Text.Length; 49 | int start = txtText.SelectionStart + (txtText.SelectedText.Equals(txtFilter.Text, IGNORECASE) ? filterlen : 0); //Skip currently found if applicable 50 | 51 | StartFind: 52 | var indexof = txtText.Text.IndexOf(txtFilter.Text, start, IGNORECASE); 53 | if (indexof == -1) 54 | { 55 | if (start == 0) //Have looped and no matches 56 | { 57 | lblFind.Visible = true; 58 | return; 59 | } 60 | 61 | start = 0; 62 | goto StartFind; //Search from the start of the text 63 | } 64 | else 65 | { 66 | txtText.SelectionStart = indexof; //Highlight the next found instance 67 | txtText.SelectionLength = filterlen; 68 | txtText.ScrollToCaret(); 69 | lblFind.Visible = false; 70 | } 71 | } 72 | 73 | private void txtText_Enter(object sender, EventArgs e) 74 | { 75 | this.AcceptButton = null; 76 | } 77 | 78 | private void txtText_Leave(object sender, EventArgs e) 79 | { 80 | this.AcceptButton = btnSave; 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /WDBXEditor/Help.chm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinsch/WDBXEditor/c4b7f1bea74a5ac98d0066885981ca2c5a58e95d/WDBXEditor/Help.chm -------------------------------------------------------------------------------- /WDBXEditor/NamedPipeManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using System.Collections.Generic; 4 | using System.ComponentModel; 5 | using System.IO; 6 | using System.IO.Pipes; 7 | using System.Linq; 8 | using System.Text; 9 | using System.Threading; 10 | using System.Threading.Tasks; 11 | 12 | namespace WDBXEditor 13 | { 14 | public class NamedPipeManager 15 | { 16 | public string NamedPipeName = "WDBXEditorPipe"; 17 | public event Action ReceiveString; 18 | 19 | private const string EXIT_STRING = "[EXIT]"; 20 | private List Workers = new List(); 21 | 22 | /// 23 | /// Starts a pipe server on a new backgroundworker 24 | /// 25 | public void StartServer() 26 | { 27 | BackgroundWorker bw = new BackgroundWorker(); 28 | Workers.Add(bw); 29 | bw.WorkerSupportsCancellation = true; 30 | bw.DoWork += Bw_DoWork; 31 | bw.RunWorkerCompleted += Bw_RunWorkerCompleted; 32 | bw.RunWorkerAsync(); 33 | } 34 | 35 | /// 36 | /// Creates a new pipe server that awaits a message 37 | /// 38 | /// 39 | /// 40 | private void Bw_DoWork(object sender, DoWorkEventArgs e) 41 | { 42 | using (var server = new NamedPipeServerStream(NamedPipeName, PipeDirection.InOut, -1)) 43 | { 44 | try 45 | { 46 | server.WaitForConnection(); 47 | using (StreamReader reader = new StreamReader(server)) 48 | e.Result = reader.ReadToEnd(); 49 | } 50 | catch { e.Result = ""; } 51 | } 52 | } 53 | 54 | /// 55 | /// Returns the message recieved and spawns a new server disposing of the previous backgroundworker 56 | /// 57 | /// 58 | /// 59 | private void Bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 60 | { 61 | string result = e.Result as string; 62 | if (result != EXIT_STRING) 63 | { 64 | StartServer(); //If not exit then start a new server instance 65 | ReceiveString?.Invoke(result); //Send signal we've received a new file to open 66 | } 67 | 68 | //Dispose background worker 69 | BackgroundWorker bw = (sender as BackgroundWorker); 70 | bw.RunWorkerCompleted -= Bw_RunWorkerCompleted; 71 | bw.DoWork -= Bw_DoWork; 72 | Task.Run(() => bw.Dispose()); 73 | } 74 | 75 | /// 76 | /// Shuts down all the pipe servers 77 | /// 78 | public void StopServer() 79 | { 80 | for (int i = 0; i < Workers.Count; i++) 81 | { 82 | BackgroundWorker bw = Workers[i]; 83 | Write(EXIT_STRING); //Send all pipes the exit command 84 | } 85 | 86 | Thread.Sleep(100); 87 | Workers.Clear(); 88 | } 89 | 90 | public bool Write(string text, int connectTimeout = 250) 91 | { 92 | using (var client = new NamedPipeClientStream(NamedPipeName)) 93 | { 94 | try 95 | { 96 | client.Connect(connectTimeout); 97 | if (!client.IsConnected) 98 | return false; 99 | 100 | using (StreamWriter writer = new StreamWriter(client)) 101 | { 102 | writer.Write(text); 103 | writer.Flush(); 104 | } 105 | } 106 | catch 107 | { 108 | return false; 109 | } 110 | } 111 | return true; 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /WDBXEditor/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Runtime.InteropServices; 4 | using System.Windows.Forms; 5 | using WDBXEditor.ConsoleHandler; 6 | 7 | namespace WDBXEditor 8 | { 9 | static class Program 10 | { 11 | public static bool PrimaryInstance = false; 12 | 13 | /// 14 | /// The main entry point for the application. 15 | /// 16 | [STAThread] 17 | static void Main(string[] args) 18 | { 19 | InstanceManager.InstanceCheck(args); //Check to see if we can run this instance 20 | InstanceManager.LoadDll("StormLib.dll"); //Loads the correct StormLib library 21 | 22 | Application.EnableVisualStyles(); 23 | Application.SetCompatibleTextRenderingDefault(false); 24 | 25 | UpdateManager.Clean(); 26 | 27 | if (args != null && args.Length > 0) 28 | { 29 | ConsoleManager.LoadCommandDefinitions(); 30 | 31 | if (ConsoleManager.CommandHandlers.ContainsKey(args[0].ToLower())) 32 | ConsoleManager.ConsoleMain(args); //Console mode 33 | else 34 | Application.Run(new Main(args)); //Load file(s) 35 | } 36 | else 37 | { 38 | Application.Run(new Main()); //Default 39 | } 40 | 41 | InstanceManager.Stop(); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /WDBXEditor/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 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("WDBXEditor")] 9 | [assembly: AssemblyDescription("A World of Warcraft client db editor.")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("WDBXEditor")] 13 | [assembly: AssemblyCopyright("Copyright Barncastle © 2016")] 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("e1f42b5c-7a40-4539-ad92-e24cad7041f5")] 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 | [assembly: AssemblyVersion("1.0.4.0")] 36 | [assembly: AssemblyFileVersion("1.0.4.0")] 37 | -------------------------------------------------------------------------------- /WDBXEditor/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 3306 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | https://github.com/WowDevTools/WDBXEditor/releases 19 | 20 | 21 | http://api.github.com/repos/WowDevTools/WDBXEditor/releases 22 | 23 | 24 | Mozilla/4.0 (Compatible; Windows NT 5.1; MSIE 6.0) (compatible; MSIE 6.0; Windows NT 5.1; WDBXEditor 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /WDBXEditor/Reader/ColumnStructureEntry.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using static WDBXEditor.Common.Constants; 7 | 8 | namespace WDBXEditor.Reader 9 | { 10 | public class ColumnStructureEntry 11 | { 12 | public ushort RecordOffset { get; set; } 13 | public ushort Size { get; set; } 14 | public uint AdditionalDataSize { get; set; } 15 | public CompressionType CompressionType { get; set; } 16 | public int BitOffset { get; set; } // used as common data column for Sparse 17 | public int BitWidth { get; set; } 18 | public int Cardinality { get; set; } // flags for Immediate, &1: Signed 19 | 20 | 21 | public List PalletValues { get; set; } 22 | public Dictionary SparseValues { get; set; } 23 | public int ArraySize { get; set; } = 1; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /WDBXEditor/Reader/DBHeader.cs: -------------------------------------------------------------------------------- 1 | using WDBXEditor.Reader.FileTypes; 2 | using WDBXEditor.Storage; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using WDBXEditor.Common; 7 | using System.Collections.Generic; 8 | using System; 9 | using static WDBXEditor.Common.Constants; 10 | 11 | namespace WDBXEditor.Reader 12 | { 13 | public class DBHeader 14 | { 15 | //Standard Fields 16 | public string Signature { get; set; } 17 | public uint RecordCount { get; set; } 18 | public uint UnknownWCH7 { get; set; } = 0; 19 | public uint FieldCount { get; set; } 20 | public uint RecordSize { get; set; } 21 | public uint StringBlockSize { get; set; } 22 | 23 | public uint TableHash { get; set; } 24 | public int LayoutHash { get; set; } 25 | public int MinId { get; set; } 26 | public int MaxId { get; set; } 27 | public int Locale { get; set; } 28 | public int CopyTableSize { get; set; } = 0; 29 | public HeaderFlags Flags { get; set; } = HeaderFlags.None; 30 | public List FieldStructure { get; set; } = new List(); 31 | public Table TableStructure { get; set; } 32 | 33 | public ushort IdIndex { get; set; } = 0; 34 | public uint TotalFieldSize { get; set; } = 0; 35 | public uint CommonDataTableSize { get; set; } = 0; 36 | public uint InternalRecordSize { get; set; } 37 | 38 | public int AutoGeneratedColumns { get; set; } = 0; 39 | public int[] OffsetLengths { get; set; } = new int[0]; 40 | public int HeaderSize = 0x20; 41 | public int StringTableOffset = 0x10; 42 | 43 | public bool IsTypeOf() => this is T; 44 | public bool IsLegionFile => this is WDB5 || this is WCH5 || this is WCH7 || this is WCH8; 45 | public bool IsValidFile => (IsTypeOf() || IsTypeOf() || IsTypeOf() || IsTypeOf() || IsLegionFile); 46 | 47 | public virtual bool ExtendedStringTable => false; 48 | public virtual bool HasIndexTable => false; 49 | public virtual bool HasOffsetTable => false; 50 | public virtual bool HasRelationshipData => false; 51 | 52 | public virtual bool CheckRecordCount => true; 53 | public virtual bool CheckRecordSize => true; 54 | public virtual bool CheckTableStructure => true; 55 | 56 | public Dictionary OffsetDuplicates = new Dictionary(); 57 | 58 | 59 | #region Read Functions 60 | 61 | public virtual void ReadHeader(ref BinaryReader dbReader, string signature) 62 | { 63 | this.Signature = signature; 64 | RecordCount = dbReader.ReadUInt32(); 65 | 66 | if (IsTypeOf()) 67 | UnknownWCH7 = dbReader.ReadUInt32(); 68 | 69 | FieldCount = dbReader.ReadUInt32(); 70 | RecordSize = dbReader.ReadUInt32(); 71 | StringBlockSize = dbReader.ReadUInt32(); 72 | } 73 | 74 | public virtual byte[] ReadData(BinaryReader dbReader, long pos) => new byte[0]; 75 | 76 | public virtual int GetStringOffset(BinaryReader dbReader, int j, uint i) => dbReader.ReadInt32(); 77 | 78 | #endregion 79 | 80 | #region Write Functions 81 | 82 | public virtual void WriteHeader(BinaryWriter bw, DBEntry entry) 83 | { 84 | //Signature 85 | bw.Write(Encoding.UTF8.GetBytes(Signature)); 86 | 87 | //Record count 88 | if (IsTypeOf() && !(this as WDB5).HasOffsetTable && entry.Header.CopyTableSize > 0) 89 | bw.Write(entry.GetUniqueRows().Count()); 90 | else 91 | bw.Write(entry.Data.Rows.Count); 92 | 93 | //WCH7 specific field 94 | if (IsTypeOf()) 95 | bw.Write(UnknownWCH7); 96 | 97 | //FieldCount 98 | if (IsTypeOf() && !IsTypeOf()) 99 | bw.Write(((WDB5)this).HasIndexTable ? FieldCount - 1 : FieldCount); //Index Table 100 | else 101 | bw.Write(FieldCount); 102 | 103 | //Record size 104 | bw.Write(RecordSize); 105 | 106 | //StringBlockSize placeholder 107 | if (IsTypeOf() || IsTypeOf()) 108 | bw.Write((uint)2); 109 | else 110 | bw.Write((uint)1); 111 | } 112 | 113 | public virtual void WriteOffsetMap(BinaryWriter bw, DBEntry entry, List> OffsetMap, int record_offset = 0) { } 114 | 115 | public virtual void WriteIndexTable(BinaryWriter bw, DBEntry entry) { } 116 | 117 | public virtual void WriteRecordPadding(BinaryWriter bw, DBEntry entry, long offset) 118 | { 119 | if (bw.BaseStream.Position - offset < RecordSize) 120 | bw.BaseStream.Position += (RecordSize - (bw.BaseStream.Position - offset)); 121 | } 122 | 123 | #endregion 124 | 125 | public virtual void Clear() { } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /WDBXEditor/Reader/FieldStructureEntry.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace WDBXEditor.Reader 8 | { 9 | public class FieldStructureEntry 10 | { 11 | public short Bits; 12 | public ushort Offset; 13 | public int Length = 1; 14 | 15 | public bool CommonDataColumn => CommonDataType != 0xFF; 16 | public byte CommonDataType; 17 | 18 | public int ByteCount 19 | { 20 | get 21 | { 22 | int value = (32 - Bits) >> 3; 23 | return (value < 0 ? Math.Abs(value) + 4 : value); 24 | } 25 | } 26 | 27 | public int BitCount 28 | { 29 | get 30 | { 31 | int bitSize = 32 - Bits; 32 | if (bitSize < 0) 33 | bitSize = (bitSize * -1) + 32; 34 | return bitSize; 35 | } 36 | } 37 | 38 | 39 | public FieldStructureEntry(short bits, ushort offset, byte commondatatype = 0xFF) 40 | { 41 | this.Bits = bits; 42 | this.Offset = offset; 43 | this.CommonDataType = commondatatype; 44 | } 45 | 46 | public void SetLength(FieldStructureEntry nextField) 47 | { 48 | this.Length = Math.Max(1, (int)Math.Floor((nextField.Offset - this.Offset) / (double)this.ByteCount)); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /WDBXEditor/Reader/FileTypes/HTFX.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using WDBXEditor.Storage; 8 | 9 | namespace WDBXEditor.Reader.FileTypes 10 | { 11 | public class HTFX : DBHeader 12 | { 13 | public int Build { get; set; } 14 | public byte[] Hashes { get; set; } 15 | public List Entries { get; private set; } = new List(); 16 | 17 | public override bool CheckRecordCount => false; 18 | public override bool CheckRecordSize => false; 19 | public override bool CheckTableStructure => false; 20 | 21 | public WDB6 WDB6CounterPart { get; private set; } 22 | 23 | public override void ReadHeader(ref BinaryReader dbReader, string signature) 24 | { 25 | this.Signature = signature; 26 | Locale = dbReader.ReadInt32(); 27 | Build = dbReader.ReadInt32(); 28 | 29 | string tempHeader = dbReader.ReadString(4); 30 | dbReader.BaseStream.Position -= 4; 31 | 32 | if (tempHeader != "XFTH") 33 | Hashes = dbReader.ReadBytes(32); 34 | 35 | while (dbReader.BaseStream.Position < dbReader.BaseStream.Length) 36 | Entries.Add(new HotfixEntry(dbReader)); 37 | 38 | Entries.RemoveAll(x => x.IsValid != 1); //Remove old hotfix entries 39 | } 40 | 41 | public bool HasEntry(DBHeader counterpart) => Entries.Any(x => (x.Locale == counterpart.Locale || x.Locale == 0) && x.TableHash == counterpart.TableHash && x.IsValid == 1); 42 | 43 | public bool Read(DBHeader counterpart, DBEntry dbentry) 44 | { 45 | WDB6CounterPart = counterpart as WDB6; 46 | if (WDB6CounterPart == null) 47 | return false; 48 | 49 | var entries = Entries.Where(x => (x.Locale == counterpart.Locale || x.Locale == 0) && x.TableHash == counterpart.TableHash); 50 | if (entries.Any()) 51 | { 52 | OffsetLengths = entries.Select(x => (int)x.Size + 4).ToArray(); 53 | TableStructure = WDB6CounterPart.TableStructure; 54 | Flags = WDB6CounterPart.Flags; 55 | FieldStructure = WDB6CounterPart.FieldStructure; 56 | RecordCount = (uint)entries.Count(); 57 | 58 | dbentry.LoadTableStructure(); 59 | 60 | IEnumerable Data = new byte[0]; 61 | foreach (var e in entries) 62 | Data = Data.Concat(BitConverter.GetBytes(e.RowId)).Concat(e.Data); 63 | 64 | using (MemoryStream ms = new MemoryStream(Data.ToArray())) 65 | using (BinaryReader br = new BinaryReader(ms)) 66 | new DBReader().ReadIntoTable(ref dbentry, br, new Dictionary()); 67 | 68 | return true; 69 | } 70 | 71 | return false; 72 | } 73 | } 74 | 75 | public class HotfixEntry 76 | { 77 | public uint Signature; 78 | public uint Locale; 79 | public uint PushId; 80 | public uint Size; 81 | public uint TableHash; 82 | public int RowId; 83 | public byte IsValid; 84 | public byte[] Padding; 85 | public byte[] Data; 86 | 87 | public HotfixEntry(BinaryReader br) 88 | { 89 | Signature = br.ReadUInt32(); 90 | Locale = br.ReadUInt32(); 91 | PushId = br.ReadUInt32(); 92 | Size = br.ReadUInt32(); 93 | TableHash = br.ReadUInt32(); 94 | RowId = br.ReadInt32(); 95 | IsValid = br.ReadByte(); 96 | Padding = br.ReadBytes(3); 97 | 98 | Data = br.ReadBytes((int)Size); 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /WDBXEditor/Reader/FileTypes/WCH7.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using WDBXEditor.Storage; 9 | 10 | namespace WDBXEditor.Reader.FileTypes 11 | { 12 | class WCH7 : WCH5 13 | { 14 | public int[] WCH7Table { get; private set; } = new int[0]; 15 | 16 | public WCH7() 17 | { 18 | StringTableOffset = 0x14; 19 | HeaderSize = 0x34; 20 | } 21 | 22 | public WCH7(string filename) 23 | { 24 | StringTableOffset = 0x14; 25 | HeaderSize = 0x34; 26 | this.FileName = filename; 27 | } 28 | 29 | public override byte[] ReadData(BinaryReader dbReader, long pos) 30 | { 31 | Dictionary CopyTable = ReadOffsetData(dbReader, pos); 32 | OffsetLengths = CopyTable.Select(x => x.Value.Length).ToArray(); 33 | return CopyTable.Values.SelectMany(x => x).ToArray(); 34 | } 35 | 36 | public new Dictionary ReadOffsetData(BinaryReader dbReader, long pos) 37 | { 38 | Dictionary CopyTable = new Dictionary(); 39 | List offsetmap = new List(); 40 | 41 | long indexTablePos = dbReader.BaseStream.Length - (HasIndexTable ? RecordCount * 4 : 0); 42 | long wch7TablePos = indexTablePos - (UnknownWCH7 * 4); 43 | int[] m_indexes = null; 44 | 45 | 46 | //Offset table - Contains the index, offset and length meaning the index table is not used 47 | if (HasOffsetTable) 48 | { 49 | // Records table 50 | if (StringBlockSize > 0) 51 | dbReader.Scrub(StringBlockSize); 52 | 53 | for (int i = 0; i < RecordCount; i++) 54 | { 55 | int id = dbReader.ReadInt32(); 56 | int offset = dbReader.ReadInt32(); 57 | short length = dbReader.ReadInt16(); 58 | 59 | if (offset == 0 || length == 0) continue; 60 | 61 | offsetmap.Add(new OffsetEntry(id, offset, length)); 62 | } 63 | } 64 | 65 | //New WCH7 table 66 | if (UnknownWCH7 > 0) 67 | { 68 | WCH7Table = new int[UnknownWCH7]; 69 | dbReader.Scrub(wch7TablePos); 70 | 71 | for (int i = 0; i < UnknownWCH7; i++) 72 | WCH7Table[i] = dbReader.ReadInt32(); 73 | } 74 | 75 | //Index table 76 | if (HasIndexTable) 77 | { 78 | if (!HasOffsetTable || HasRelationshipData) 79 | dbReader.Scrub(indexTablePos); 80 | 81 | m_indexes = new int[RecordCount]; 82 | for (int i = 0; i < RecordCount; i++) 83 | m_indexes[i] = dbReader.ReadInt32(); 84 | } 85 | 86 | //Extract record data 87 | for (int i = 0; i < Math.Max(RecordCount, offsetmap.Count); i++) 88 | { 89 | if (HasOffsetTable) 90 | { 91 | var map = offsetmap[i]; 92 | dbReader.Scrub(map.Offset); 93 | 94 | IEnumerable recordbytes = BitConverter.GetBytes(map.Id).Concat(dbReader.ReadBytes(map.Length)); 95 | CopyTable.Add(map.Id, recordbytes.ToArray()); 96 | } 97 | else 98 | { 99 | dbReader.Scrub(pos + i * RecordSize); 100 | byte[] recordbytes = dbReader.ReadBytes((int)RecordSize); 101 | 102 | if (HasIndexTable) 103 | { 104 | IEnumerable newrecordbytes = BitConverter.GetBytes(m_indexes[i]).Concat(recordbytes); 105 | CopyTable.Add(m_indexes[i], newrecordbytes.ToArray()); 106 | } 107 | else 108 | { 109 | int bytecount = FieldStructure[IdIndex].ByteCount; 110 | int offset = FieldStructure[IdIndex].Offset; 111 | 112 | int id = 0; 113 | for (int j = 0; j < bytecount; j++) 114 | id |= (recordbytes[offset + j] << (j * 8)); 115 | 116 | CopyTable.Add(id, recordbytes); 117 | } 118 | } 119 | } 120 | 121 | return CopyTable; 122 | } 123 | 124 | public override void WriteRecordPadding(BinaryWriter bw, DBEntry entry, long offset) 125 | { 126 | if (bw.BaseStream.Position - offset < RecordSize) 127 | bw.BaseStream.Position += (RecordSize - (bw.BaseStream.Position - offset)); 128 | } 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /WDBXEditor/Reader/FileTypes/WCH8.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using WDBXEditor.Storage; 8 | 9 | namespace WDBXEditor.Reader.FileTypes 10 | { 11 | class WCH8 : WCH7 12 | { 13 | public WCH8() 14 | { 15 | StringTableOffset = 0x14; 16 | HeaderSize = 0x34; 17 | } 18 | 19 | public WCH8(string filename) 20 | { 21 | StringTableOffset = 0x14; 22 | HeaderSize = 0x34; 23 | this.FileName = filename; 24 | } 25 | 26 | public override void WriteRecordPadding(BinaryWriter bw, DBEntry entry, long offset) 27 | { 28 | if (!HasOffsetTable && bw.BaseStream.Position - offset < RecordSize) 29 | bw.BaseStream.Position += (RecordSize - (bw.BaseStream.Position - offset)); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /WDBXEditor/Reader/FileTypes/WDB.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using WDBXEditor.Common; 8 | using WDBXEditor.Storage; 9 | 10 | namespace WDBXEditor.Reader.FileTypes 11 | { 12 | public class WDB : DBHeader 13 | { 14 | public new string Locale { get; set; } 15 | public int RecordVersion { get; set; } 16 | public int CacheVersion { get; set; } 17 | public int Build { get; set; } 18 | public override bool CheckRecordCount => false; 19 | 20 | public override void ReadHeader(ref BinaryReader dbReader, string signature) 21 | { 22 | this.Signature = signature; 23 | Build = dbReader.ReadInt32(); 24 | 25 | if (Build >= 4500) // 1.6.0 26 | Locale = dbReader.ReadString(4).Reverse(); 27 | 28 | RecordSize = dbReader.ReadUInt32(); 29 | RecordVersion = dbReader.ReadInt32(); 30 | 31 | if (Build >= 9506) // 3.0.8 32 | CacheVersion = dbReader.ReadInt32(); 33 | } 34 | 35 | public byte[] ReadData(BinaryReader dbReader) 36 | { 37 | List data = new List(); 38 | 39 | //Stored as Index, Size then Data 40 | while (dbReader.BaseStream.Position != dbReader.BaseStream.Length) 41 | { 42 | int index = dbReader.ReadInt32(); 43 | if (index == 0 && dbReader.BaseStream.Position == dbReader.BaseStream.Length) 44 | break; 45 | 46 | int size = dbReader.ReadInt32(); 47 | if (index == 0 && size == 0 && dbReader.BaseStream.Position == dbReader.BaseStream.Length) 48 | break; 49 | 50 | data.AddRange(BitConverter.GetBytes(index)); 51 | data.AddRange(dbReader.ReadBytes(size)); 52 | 53 | RecordCount++; 54 | } 55 | 56 | return data.ToArray(); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /WDBXEditor/Reader/FileTypes/WDB2.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using WDBXEditor.Storage; 8 | using System.Data; 9 | using System.Diagnostics; 10 | 11 | namespace WDBXEditor.Reader.FileTypes 12 | { 13 | public class WDB2 : DBHeader 14 | { 15 | public int Build { get; set; } 16 | public int TimeStamp { get; set; } 17 | public int[] IndexMap { get; set; } //Maps index to row for all indicies between min and max 18 | public short[] StringLengths { get; set; } //Length of each string including the 0 byte character 19 | 20 | public override bool ExtendedStringTable => Build > 18273; //WoD has two null bytes 21 | 22 | public override void ReadHeader(ref BinaryReader dbReader, string signature) 23 | { 24 | base.ReadHeader(ref dbReader, signature); 25 | 26 | TableHash = dbReader.ReadUInt32(); 27 | Build = dbReader.ReadInt32(); 28 | TimeStamp = dbReader.ReadInt32(); 29 | MinId = dbReader.ReadInt32(); 30 | MaxId = dbReader.ReadInt32(); 31 | Locale = dbReader.ReadInt32(); 32 | CopyTableSize = dbReader.ReadInt32(); 33 | 34 | if (MaxId != 0 && Build > 12880) 35 | { 36 | int diff = MaxId - MinId + 1; //Calculate the array sizes 37 | IndexMap = new int[diff]; 38 | StringLengths = new short[diff]; 39 | 40 | //Populate the arrays 41 | for (int i = 0; i < diff; i++) 42 | IndexMap[i] = dbReader.ReadInt32(); 43 | 44 | for (int i = 0; i < diff; i++) 45 | StringLengths[i] = dbReader.ReadInt16(); 46 | } 47 | } 48 | 49 | public override void WriteHeader(BinaryWriter bw, DBEntry entry) 50 | { 51 | base.WriteHeader(bw, entry); 52 | 53 | Tuple minmax = entry.MinMax(); 54 | if (MaxId == 0) //Irrelevant if header doesn't use this 55 | minmax = new Tuple(0, 0); 56 | 57 | bw.Write(TableHash); 58 | bw.Write(Build); 59 | bw.Write(TimeStamp); 60 | 61 | bw.Write(minmax.Item1); 62 | bw.Write(minmax.Item2); 63 | 64 | bw.Write(Locale); 65 | bw.Write(CopyTableSize); 66 | 67 | if (MaxId != 0 && Build > 12880) 68 | { 69 | List IndiciesTable = new List(); 70 | List StringLengthTable = new List(); 71 | 72 | Dictionary stringlengths = entry.GetStringLengths(); 73 | int x = 0; 74 | for (int i = minmax.Item1; i <= minmax.Item2; i++) 75 | { 76 | if (stringlengths.ContainsKey(i)) 77 | { 78 | StringLengthTable.Add(stringlengths[i]); 79 | IndiciesTable.Add(++x); 80 | } 81 | else 82 | { 83 | IndiciesTable.Add(0); 84 | StringLengthTable.Add(0); 85 | } 86 | } 87 | 88 | //Write the data 89 | bw.WriteArray(IndiciesTable.ToArray()); 90 | bw.WriteArray(StringLengthTable.ToArray()); 91 | } 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /WDBXEditor/Reader/FileTypes/WDBC.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using WDBXEditor.Storage; 8 | 9 | namespace WDBXEditor.Reader.FileTypes 10 | { 11 | public class WDBC : DBHeader 12 | { 13 | public override void ReadHeader(ref BinaryReader dbReader, string signature) 14 | { 15 | base.ReadHeader(ref dbReader, signature); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /WDBXEditor/Reader/MemoryReader.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Diagnostics; 5 | using System.Linq; 6 | using System.Runtime.InteropServices; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace WDBXEditor.Reader 11 | { 12 | public class MemoryReader : IDisposable 13 | { 14 | public ulong BaseAddress { get; private set; } 15 | public IntPtr ProcessHandle { get; private set; } 16 | 17 | private Process process; 18 | 19 | public MemoryReader(Process proc) 20 | { 21 | if ((proc?.Id ?? 0) == 0) 22 | throw new Exception("Invalid process"); 23 | 24 | BaseAddress = (ulong)proc.MainModule.BaseAddress; 25 | ProcessHandle = OpenProcess(ProcessAccess.AllAccess, false, proc.Id); 26 | 27 | if (ProcessHandle == IntPtr.Zero) 28 | throw new Win32Exception("Failed to open the process for reading."); 29 | 30 | Process.EnterDebugMode(); 31 | process = proc; 32 | } 33 | 34 | public void Dispose() 35 | { 36 | if (ProcessHandle != IntPtr.Zero && !CloseHandle(ProcessHandle)) 37 | throw new Win32Exception(Marshal.GetLastWin32Error()); 38 | 39 | GC.SuppressFinalize(this); 40 | } 41 | 42 | ~MemoryReader() 43 | { 44 | Dispose(); 45 | } 46 | 47 | public byte[] ReadBytes(IntPtr address, uint count) 48 | { 49 | var buffer = new byte[count]; 50 | int bytesRead; 51 | if (!ReadProcessMemory(ProcessHandle, address, buffer, count, out bytesRead)) 52 | throw new Win32Exception(Marshal.GetLastWin32Error()); 53 | 54 | if (bytesRead != count) 55 | throw new Exception("Bytes read did not match required byte count!"); 56 | return buffer; 57 | } 58 | 59 | public T Read(IntPtr address) where T : struct 60 | { 61 | object ret = default(T); 62 | var buffer = new byte[0]; 63 | 64 | if (typeof(T) == typeof(string)) 65 | return (T)(object)ReadCString(address); 66 | else 67 | buffer = ReadBytes(address, (uint)Marshal.SizeOf(typeof(T))); 68 | 69 | switch (Type.GetTypeCode(typeof(T))) 70 | { 71 | case TypeCode.Object: 72 | GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned); 73 | Marshal.PtrToStructure(handle.AddrOfPinnedObject(), ret); 74 | handle.Free(); 75 | break; 76 | case TypeCode.Boolean: 77 | ret = BitConverter.ToBoolean(buffer, 0); 78 | break; 79 | case TypeCode.Char: 80 | ret = BitConverter.ToChar(buffer, 0); 81 | break; 82 | case TypeCode.Byte: 83 | ret = buffer[0]; 84 | break; 85 | case TypeCode.Int16: 86 | ret = BitConverter.ToInt16(buffer, 0); 87 | break; 88 | case TypeCode.UInt16: 89 | ret = BitConverter.ToUInt16(buffer, 0); 90 | break; 91 | case TypeCode.Int32: 92 | ret = BitConverter.ToInt32(buffer, 0); 93 | break; 94 | case TypeCode.UInt32: 95 | ret = BitConverter.ToUInt32(buffer, 0); 96 | break; 97 | case TypeCode.Int64: 98 | ret = BitConverter.ToInt64(buffer, 0); 99 | break; 100 | case TypeCode.UInt64: 101 | ret = BitConverter.ToUInt64(buffer, 0); 102 | break; 103 | case TypeCode.Single: 104 | ret = BitConverter.ToSingle(buffer, 0); 105 | break; 106 | case TypeCode.Double: 107 | ret = BitConverter.ToDouble(buffer, 0); 108 | break; 109 | default: 110 | throw new NotSupportedException($"Unknown type {typeof(T).Name}."); 111 | } 112 | 113 | return (T)ret; 114 | } 115 | 116 | public string ReadCString(IntPtr address) 117 | { 118 | var buffer = new List(); 119 | 120 | int i = 0; 121 | byte current = Read((IntPtr)(address.ToInt32() + i)); 122 | while (current != 0) 123 | { 124 | buffer.Add(current); 125 | i++; 126 | current = Read((IntPtr)(address.ToInt32() + i)); 127 | } 128 | return Encoding.UTF8.GetString(buffer.ToArray()); 129 | } 130 | 131 | #region PInvokes 132 | 133 | [DllImport("kernel32.dll", SetLastError = true, PreserveSig = true)] 134 | [return: MarshalAs(UnmanagedType.Bool)] 135 | private static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, uint nSize, out int lpNumberOfBytesRead); 136 | 137 | [DllImport("kernel32.dll")] 138 | private static extern IntPtr OpenProcess(ProcessAccess dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, int dwProcessId); 139 | 140 | [DllImport("kernel32.dll", SetLastError = true)] 141 | [return: MarshalAs(UnmanagedType.Bool)] 142 | private static extern bool CloseHandle(IntPtr hObject); 143 | 144 | private enum ProcessAccess 145 | { 146 | AllAccess = 0x2 | 0x40 | 0x400 | 0x200 | 0x1 | 0x8 | 0x10 | 0x20 | 0x100000 147 | } 148 | #endregion 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /WDBXEditor/Reader/RelationShipData.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace WDBXEditor.Reader 8 | { 9 | public class RelationShipData 10 | { 11 | public uint Records; 12 | public uint MinId; 13 | public uint MaxId; 14 | public Dictionary Entries; // index, id 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /WDBXEditor/Reader/StringTable.cs: -------------------------------------------------------------------------------- 1 | using WDBXEditor.Common; 2 | using WDBXEditor.Reader; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Text; 6 | using System; 7 | 8 | namespace WDBXEditor.Reader 9 | { 10 | public class StringTable : IDisposable 11 | { 12 | public Dictionary Table = new Dictionary(); 13 | public int Size => (int)StringStream.Length; 14 | 15 | public MemoryStream StringStream = new MemoryStream(); 16 | private Dictionary _stringlookup = new Dictionary(); 17 | 18 | public StringTable() { } 19 | 20 | public StringTable(bool extended) 21 | { 22 | StringStream.WriteByte(0); 23 | if (extended) 24 | StringStream.WriteByte(0); 25 | } 26 | 27 | /// 28 | /// Writes the string into the stringtable and return's it's position. 29 | /// If unique then it will check if the string is existent and return the previous position. 30 | /// 31 | /// 32 | /// 33 | /// 34 | public int Write(string str, bool duplicates = false, bool stripCR = true) 35 | { 36 | if (stripCR) 37 | str = str.Replace("\r\n", "\n").Replace(Environment.NewLine, "\n"); 38 | 39 | int offset = 0; 40 | if (str == "") //Empty string always 0 41 | return offset; 42 | 43 | //WDB2 with MaxId allows duplicates else distinct strings 44 | if (duplicates || !_stringlookup.TryGetValue(str, out offset)) 45 | { 46 | byte[] strBytes = Encoding.UTF8.GetBytes(str); 47 | offset = (int)StringStream.Position; 48 | 49 | if (!duplicates) 50 | _stringlookup.Add(str, offset); 51 | 52 | StringStream.Write(strBytes, 0, strBytes.Length); 53 | StringStream.WriteByte(0); 54 | } 55 | 56 | return offset; 57 | } 58 | 59 | public void CopyTo(Stream s) 60 | { 61 | StringStream.Position = 0; 62 | StringStream.CopyTo(s); 63 | } 64 | 65 | 66 | /// 67 | /// Reads the binary data from start to end returning a list of strings and their positions. 68 | /// 69 | /// 70 | /// 71 | /// 72 | /// 73 | public Dictionary Read(BinaryReader dbReader, long stringTableStart, long stringTableEnd, bool absolute = false) 74 | { 75 | if (dbReader.BaseStream.Position > stringTableEnd) 76 | return Table; 77 | 78 | while (dbReader.BaseStream.Position < stringTableEnd) 79 | { 80 | int pos = (int)dbReader.BaseStream.Position; 81 | int index = (int)(pos - stringTableStart); 82 | Table[absolute ? pos : index] = dbReader.ReadStringNull(); 83 | } 84 | 85 | return Table; 86 | } 87 | 88 | public Dictionary Read(BinaryReader dbReader, long stringTableStart) 89 | { 90 | return Read(dbReader, stringTableStart, dbReader.BaseStream.Length); 91 | } 92 | 93 | public void Dispose() 94 | { 95 | ((IDisposable)StringStream).Dispose(); 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /WDBXEditor/Resources/LoadDef.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinsch/WDBXEditor/c4b7f1bea74a5ac98d0066885981ca2c5a58e95d/WDBXEditor/Resources/LoadDef.png -------------------------------------------------------------------------------- /WDBXEditor/Resources/close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinsch/WDBXEditor/c4b7f1bea74a5ac98d0066885981ca2c5a58e95d/WDBXEditor/Resources/close.png -------------------------------------------------------------------------------- /WDBXEditor/Resources/csv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinsch/WDBXEditor/c4b7f1bea74a5ac98d0066885981ca2c5a58e95d/WDBXEditor/Resources/csv.png -------------------------------------------------------------------------------- /WDBXEditor/Resources/hide.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinsch/WDBXEditor/c4b7f1bea74a5ac98d0066885981ca2c5a58e95d/WDBXEditor/Resources/hide.png -------------------------------------------------------------------------------- /WDBXEditor/Resources/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinsch/WDBXEditor/c4b7f1bea74a5ac98d0066885981ca2c5a58e95d/WDBXEditor/Resources/icon.ico -------------------------------------------------------------------------------- /WDBXEditor/Resources/open-new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinsch/WDBXEditor/c4b7f1bea74a5ac98d0066885981ca2c5a58e95d/WDBXEditor/Resources/open-new.png -------------------------------------------------------------------------------- /WDBXEditor/Resources/open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinsch/WDBXEditor/c4b7f1bea74a5ac98d0066885981ca2c5a58e95d/WDBXEditor/Resources/open.png -------------------------------------------------------------------------------- /WDBXEditor/Resources/paintbrush.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinsch/WDBXEditor/c4b7f1bea74a5ac98d0066885981ca2c5a58e95d/WDBXEditor/Resources/paintbrush.png -------------------------------------------------------------------------------- /WDBXEditor/Resources/reload.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinsch/WDBXEditor/c4b7f1bea74a5ac98d0066885981ca2c5a58e95d/WDBXEditor/Resources/reload.png -------------------------------------------------------------------------------- /WDBXEditor/Resources/save_file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinsch/WDBXEditor/c4b7f1bea74a5ac98d0066885981ca2c5a58e95d/WDBXEditor/Resources/save_file.png -------------------------------------------------------------------------------- /WDBXEditor/Resources/search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinsch/WDBXEditor/c4b7f1bea74a5ac98d0066885981ca2c5a58e95d/WDBXEditor/Resources/search.png -------------------------------------------------------------------------------- /WDBXEditor/Resources/sql.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinsch/WDBXEditor/c4b7f1bea74a5ac98d0066885981ca2c5a58e95d/WDBXEditor/Resources/sql.png -------------------------------------------------------------------------------- /WDBXEditor/Resources/sqlfile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinsch/WDBXEditor/c4b7f1bea74a5ac98d0066885981ca2c5a58e95d/WDBXEditor/Resources/sqlfile.png -------------------------------------------------------------------------------- /WDBXEditor/Resources/table.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinsch/WDBXEditor/c4b7f1bea74a5ac98d0066885981ca2c5a58e95d/WDBXEditor/Resources/table.png -------------------------------------------------------------------------------- /WDBXEditor/Resources/target.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinsch/WDBXEditor/c4b7f1bea74a5ac98d0066885981ca2c5a58e95d/WDBXEditor/Resources/target.png -------------------------------------------------------------------------------- /WDBXEditor/Resources/tick.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinsch/WDBXEditor/c4b7f1bea74a5ac98d0066885981ca2c5a58e95d/WDBXEditor/Resources/tick.png -------------------------------------------------------------------------------- /WDBXEditor/Resources/toggle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinsch/WDBXEditor/c4b7f1bea74a5ac98d0066885981ca2c5a58e95d/WDBXEditor/Resources/toggle.png -------------------------------------------------------------------------------- /WDBXEditor/Storage/Database.cs: -------------------------------------------------------------------------------- 1 | using WDBXEditor.Reader; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | using static WDBXEditor.Common.Constants; 8 | using System.Threading.Tasks.Dataflow; 9 | using System.Data; 10 | using System.Collections.Concurrent; 11 | using System.Diagnostics; 12 | using System.Windows.Forms; 13 | 14 | namespace WDBXEditor.Storage 15 | { 16 | class Database 17 | { 18 | public static Definition Definitions { get; set; } = new Definition(); 19 | public static List Entries { get; set; } = new List(); 20 | public static int BuildNumber { get; set; } 21 | 22 | 23 | #region Load 24 | internal enum ErrorType 25 | { 26 | Warning, 27 | Error 28 | } 29 | 30 | private static string FormatError(string f, ErrorType t, string s) 31 | { 32 | return $"{t.ToString().ToUpper()} {Path.GetFileName(f)} : {s}"; 33 | } 34 | 35 | public static async Task> LoadFiles(IEnumerable filenames) 36 | { 37 | ConcurrentBag _errors = new ConcurrentBag(); 38 | ConcurrentQueue files = new ConcurrentQueue(filenames.Distinct().OrderBy(x => x).ThenByDescending(x => Path.GetExtension(x))); 39 | string firstFile = files.First(); 40 | 41 | var batchBlock = new BatchBlock(100, new GroupingDataflowBlockOptions { BoundedCapacity = 100 }); 42 | var actionBlock = new ActionBlock(t => 43 | { 44 | for (int i = 0; i < t.Length; i++) 45 | { 46 | files.TryDequeue(out string file); 47 | try 48 | { 49 | DBReader reader = new DBReader(); 50 | DBEntry entry = reader.Read(file); 51 | if (entry != null) 52 | { 53 | var current = Entries.FirstOrDefault(x => x.FileName == entry.FileName && x.Build == entry.Build); 54 | if (current != null) 55 | Entries.Remove(current); 56 | 57 | Entries.Add(entry); 58 | //if (file != firstFile) 59 | // entry.Detach(); 60 | 61 | if (!string.IsNullOrWhiteSpace(reader.ErrorMessage)) 62 | _errors.Add(FormatError(file, ErrorType.Warning, reader.ErrorMessage)); 63 | } 64 | } 65 | catch (Exception ex) { _errors.Add(FormatError(file, ErrorType.Error, ex.Message)); } 66 | } 67 | 68 | ForceGC(); 69 | }); 70 | batchBlock.LinkTo(actionBlock, new DataflowLinkOptions { PropagateCompletion = true }); 71 | 72 | foreach (string i in files) 73 | await batchBlock.SendAsync(i); // wait synchronously for the block to accept. 74 | 75 | batchBlock.Complete(); 76 | await actionBlock.Completion; 77 | 78 | files = null; 79 | return _errors.ToList(); 80 | } 81 | 82 | public static async Task> LoadFiles(ConcurrentDictionary streams) 83 | { 84 | List _errors = new List(); 85 | Queue> files = new Queue>(streams); 86 | 87 | var batchBlock = new BatchBlock>(75, new GroupingDataflowBlockOptions { BoundedCapacity = 100 }); 88 | var actionBlock = new ActionBlock[]>(t => 89 | { 90 | for (int i = 0; i < t.Length; i++) 91 | { 92 | var s = files.Dequeue(); 93 | try 94 | { 95 | DBReader reader = new DBReader(); 96 | DBEntry entry = reader.Read(s.Value, s.Key); 97 | if (entry != null) 98 | { 99 | var current = Entries.FirstOrDefault(x => x.FileName == entry.FileName && x.Build == entry.Build); 100 | if (current != null) 101 | Entries.Remove(current); 102 | 103 | Entries.Add(entry); 104 | 105 | if (!string.IsNullOrWhiteSpace(reader.ErrorMessage)) 106 | _errors.Add(FormatError(s.Key, ErrorType.Warning, reader.ErrorMessage)); 107 | } 108 | } 109 | catch (ConstraintException) 110 | { 111 | _errors.Add(FormatError(s.Key, ErrorType.Error, "Id column contains duplicates.")); 112 | } 113 | catch (Exception ex) 114 | { 115 | _errors.Add(FormatError(s.Key, ErrorType.Error, ex.Message)); 116 | } 117 | 118 | if (i % 100 == 0 && i > 0) 119 | ForceGC(); 120 | } 121 | 122 | ForceGC(); 123 | }); 124 | batchBlock.LinkTo(actionBlock, new DataflowLinkOptions { PropagateCompletion = true }); 125 | 126 | foreach (KeyValuePair i in streams) 127 | await batchBlock.SendAsync(i); // wait synchronously for the block to accept. 128 | 129 | batchBlock.Complete(); 130 | await actionBlock.Completion; 131 | 132 | ForceGC(); 133 | 134 | return _errors; 135 | } 136 | #endregion 137 | 138 | #region Save 139 | public static async Task> SaveFiles(string path) 140 | { 141 | List _errors = new List(); 142 | Queue files = new Queue(Entries); 143 | 144 | var batchBlock = new BatchBlock(100, new GroupingDataflowBlockOptions { BoundedCapacity = 100 }); 145 | var actionBlock = new ActionBlock(t => 146 | { 147 | for (int i = 0; i < t.Length; i++) 148 | { 149 | DBEntry file = files.Dequeue(); 150 | try 151 | { 152 | new DBReader().Write(file, Path.Combine(path, file.FileName)); 153 | } 154 | catch (Exception ex) { _errors.Add($"{file} : {ex.Message}"); } 155 | } 156 | 157 | ForceGC(); 158 | }); 159 | batchBlock.LinkTo(actionBlock, new DataflowLinkOptions { PropagateCompletion = true }); 160 | 161 | foreach (int i in Enumerable.Range(0, Entries.Count)) 162 | await batchBlock.SendAsync(i); // wait synchronously for the block to accept. 163 | 164 | batchBlock.Complete(); 165 | await actionBlock.Completion; 166 | 167 | return _errors; 168 | } 169 | #endregion 170 | 171 | #region Defintions 172 | public static async Task LoadDefinitions() 173 | { 174 | await Task.Factory.StartNew(() => 175 | { 176 | foreach (var file in Directory.GetFiles(DEFINITION_DIR, "*.xml")) 177 | Definitions.LoadDefinition(file); 178 | }); 179 | } 180 | #endregion 181 | 182 | public static void ForceGC() 183 | { 184 | GC.Collect(); 185 | GC.WaitForFullGCComplete(); 186 | 187 | #if DEBUG 188 | Debug.WriteLine((GC.GetTotalMemory(false) / 1024 / 1024).ToString() + "mb"); 189 | #endif 190 | } 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /WDBXEditor/Storage/Definition.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using System.Xml.Serialization; 9 | using static WDBXEditor.Common.Constants; 10 | 11 | namespace WDBXEditor.Storage 12 | { 13 | [Serializable] 14 | public class Definition 15 | { 16 | [XmlElement("Table")] 17 | public HashSet Tables { get; set; } = new HashSet
(); 18 | [XmlIgnore] 19 | public int Build { get; set; } 20 | [XmlIgnore] 21 | private bool _loading = false; 22 | 23 | public bool LoadDefinition(string path) 24 | { 25 | if (_loading) return true; 26 | 27 | try 28 | { 29 | XmlSerializer deser = new XmlSerializer(typeof(Definition)); 30 | using (var fs = new FileStream(path, FileMode.Open)) 31 | { 32 | Definition def = (Definition)deser.Deserialize(fs); 33 | var newtables = def.Tables.Where(x => Tables.Count(y => x.Build == y.Build && x.Name == y.Name) == 0).ToList(); 34 | newtables.ForEach(x => x.Load()); 35 | Tables.UnionWith(newtables.Where(x => x.Key != null)); 36 | return true; 37 | } 38 | } 39 | catch { return false; } 40 | } 41 | 42 | public bool SaveDefinitions() 43 | { 44 | string ValidFilename(string b) 45 | { 46 | return string.Join("_", b.Split(Path.GetInvalidFileNameChars(), StringSplitOptions.RemoveEmptyEntries)).TrimEnd('.') + ".xml"; 47 | } 48 | 49 | try 50 | { 51 | _loading = true; 52 | 53 | var builds = Tables.OrderBy(x => x.Name).GroupBy(x => x.Build).ToList(); 54 | Tables.Clear(); 55 | foreach (var build in builds) 56 | { 57 | Definition _def = new Definition 58 | { 59 | Build = build.Key, 60 | Tables = new HashSet
(build) 61 | }; 62 | 63 | XmlSerializer ser = new XmlSerializer(typeof(Definition)); 64 | using (var fs = new FileStream(Path.Combine(DEFINITION_DIR, ValidFilename(BuildText(build.Key))), FileMode.Create)) 65 | ser.Serialize(fs, _def); 66 | } 67 | 68 | _loading = false; 69 | return true; 70 | } 71 | catch (Exception) 72 | { 73 | _loading = false; 74 | return false; 75 | } 76 | } 77 | } 78 | 79 | [Serializable] 80 | public class Table 81 | { 82 | [XmlAttribute] 83 | public string Name { get; set; } 84 | [XmlAttribute] 85 | public int Build { get; set; } 86 | [XmlElement("Field")] 87 | public List Fields { get; set; } 88 | [XmlIgnore] 89 | public Field Key { get; private set; } 90 | [XmlIgnore] 91 | public bool Changed { get; set; } = false; 92 | [XmlIgnore] 93 | public string BuildText { get; private set; } 94 | 95 | public void Load() 96 | { 97 | Key = Fields.FirstOrDefault(x => x.IsIndex); 98 | BuildText = BuildText(Build); 99 | } 100 | } 101 | 102 | [Serializable] 103 | public class Field 104 | { 105 | [XmlAttribute] 106 | public string Name { get; set; } 107 | [XmlAttribute] 108 | public string Type { get; set; } 109 | [XmlAttribute, DefaultValue(1)] 110 | public int ArraySize { get; set; } = 1; 111 | [XmlAttribute, DefaultValue(false)] 112 | public bool IsIndex { get; set; } = false; 113 | [XmlAttribute, DefaultValue(false)] 114 | public bool AutoGenerate { get; set; } = false; 115 | [XmlAttribute, DefaultValue("")] 116 | public string DefaultValue { get; set; } = ""; 117 | [XmlAttribute, DefaultValue("")] 118 | public string ColumnNames { get; set; } = ""; 119 | [XmlIgnore] 120 | public string InternalName { get; set; } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /WDBXEditor/UpdateManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Net; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using System.Web.Script.Serialization; 9 | using System.Windows.Forms; 10 | using WDBXEditor.Common; 11 | using System.IO.Compression; 12 | 13 | namespace WDBXEditor 14 | { 15 | static class UpdateManager 16 | { 17 | private const string TEMP_DIRECTORY = ".tmp"; 18 | private static readonly string CUR_DIRECTORY = Application.StartupPath; 19 | private static readonly string TEMP_UPDATE_ZIP = Path.Combine(CUR_DIRECTORY, "update.zip"); 20 | 21 | private static bool RestartOnComplete = false; 22 | 23 | public static void Clean() 24 | { 25 | if (Directory.Exists(TEMP_DIRECTORY)) 26 | Directory.Delete(TEMP_DIRECTORY, true); 27 | } 28 | 29 | public static async Task CheckForUpdate() 30 | { 31 | if (File.Exists(TEMP_UPDATE_ZIP)) 32 | { 33 | ExtractFiles(); 34 | } 35 | else 36 | { 37 | using (var client = new WebClient()) 38 | { 39 | string releaseURL = Properties.Settings.Default["ReleaseURL"].ToString(); 40 | string releaseAPI = Properties.Settings.Default["ReleaseAPI"].ToString(); 41 | string userAgent = Properties.Settings.Default["UserAgent"].ToString(); 42 | client.Headers["User-Agent"] = userAgent + Constants.VERSION; 43 | 44 | string json = await client.DownloadStringTaskAsync(releaseAPI); 45 | var serializer = new JavaScriptSerializer(); 46 | 47 | GithubReleaseModel model = serializer.Deserialize(json); 48 | if (model != null && model.tag_name != Constants.VERSION) 49 | { 50 | string text = $"An update is available.\r\n Click \"Yes\" to upgrade to {model.tag_name}. (This will restart the application)"; 51 | 52 | DialogResult dialogResult = MessageBox.Show(text, "Update Available", MessageBoxButtons.YesNo); 53 | RestartOnComplete = (dialogResult == DialogResult.Yes); 54 | await DoDownload(model.assets[0].browser_download_url); 55 | } 56 | } 57 | } 58 | } 59 | 60 | private static async Task DoDownload(string releaseURL) 61 | { 62 | using (var client = new WebClient()) 63 | { 64 | string userAgent = Properties.Settings.Default["UserAgent"].ToString(); 65 | client.Headers["User-Agent"] = userAgent + Constants.VERSION; 66 | 67 | try 68 | { 69 | byte[] buffer = await client.DownloadDataTaskAsync(releaseURL); 70 | using (var fs = File.Create(TEMP_UPDATE_ZIP)) 71 | fs.Write(buffer, 0, buffer.Length); 72 | } 73 | catch 74 | { 75 | File.Delete(TEMP_UPDATE_ZIP); 76 | return; 77 | } 78 | 79 | ExtractFiles(); 80 | } 81 | } 82 | 83 | private static void ExtractFiles() 84 | { 85 | UPDATE_STATE state = UPDATE_STATE.SUCCESS; 86 | string backupdirectory = Path.Combine(CUR_DIRECTORY, TEMP_DIRECTORY); 87 | var fileMap = new Dictionary(); 88 | 89 | Directory.CreateDirectory(backupdirectory); 90 | 91 | try 92 | { 93 | using (var archive = ZipFile.OpenRead(TEMP_UPDATE_ZIP)) 94 | { 95 | foreach (ZipArchiveEntry file in archive.Entries) 96 | { 97 | if (string.IsNullOrWhiteSpace(file.Name)) 98 | continue; 99 | 100 | string originalFileName = Path.Combine(CUR_DIRECTORY, file.FullName); 101 | string backupFolder = Path.Combine(backupdirectory, Path.GetDirectoryName(file.FullName)); 102 | string backupFileName = Path.Combine(backupFolder, file.Name); 103 | 104 | // store file old, new paths for rollback 105 | fileMap[originalFileName] = backupFileName; 106 | 107 | try 108 | { 109 | Directory.CreateDirectory(backupFolder); 110 | File.Move(originalFileName, backupFileName); // attempt to backup and replace old files 111 | file.ExtractToFile(originalFileName, true); 112 | } 113 | catch 114 | { 115 | state = UPDATE_STATE.FAILED_FILE; // access error usually 116 | break; 117 | } 118 | } 119 | } 120 | } 121 | catch // FileNotFoundException InvalidDataException 122 | { 123 | state = UPDATE_STATE.FAILED_ZIP; 124 | } 125 | 126 | // remove the update folder regardless of success/broken zip 127 | File.Delete(TEMP_UPDATE_ZIP); 128 | 129 | // either rollback if an error or restart 130 | if (state == UPDATE_STATE.SUCCESS && RestartOnComplete) 131 | Application.Restart(); 132 | else 133 | Rollback(fileMap); 134 | 135 | if (state != UPDATE_STATE.SUCCESS && RestartOnComplete) 136 | { 137 | MessageBox.Show( 138 | "Updating failed.\r\n WDBX Editor will try again next restart. You can also manually extract `Update.zip`.", 139 | "Update Failed", 140 | MessageBoxButtons.OK, 141 | MessageBoxIcon.Exclamation 142 | ); 143 | } 144 | } 145 | 146 | private static void Rollback(Dictionary fileMap) 147 | { 148 | foreach (var map in fileMap) 149 | { 150 | File.Delete(map.Key); 151 | File.Move(map.Value, map.Key); // move everything back 152 | } 153 | Clean(); 154 | } 155 | 156 | internal enum UPDATE_STATE 157 | { 158 | FAILED_ZIP, 159 | FAILED_FILE, 160 | SUCCESS 161 | } 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /WDBXEditor/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /WDBXEditor/x64/StormLib.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinsch/WDBXEditor/c4b7f1bea74a5ac98d0066885981ca2c5a58e95d/WDBXEditor/x64/StormLib.dll -------------------------------------------------------------------------------- /WDBXEditor/x86/StormLib.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinsch/WDBXEditor/c4b7f1bea74a5ac98d0066885981ca2c5a58e95d/WDBXEditor/x86/StormLib.dll -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 1.0.{build} 2 | image: Visual Studio 2017 3 | configuration: 4 | - Release 5 | before_build: 6 | - nuget restore 7 | build: 8 | parallel: true 9 | project: WDBXEditor.sln 10 | verbosity: quiet 11 | after_build: 12 | - ps: rm .\WDBXEditor\bin\Release\*.pdb 13 | - ps: rm .\WDBXEditor\bin\Release\System.Threading.Tasks.Dataflow.xml 14 | - 7z a WDBXEditor.zip %APPVEYOR_BUILD_FOLDER%\WDBXEditor\bin\Release 15 | artifacts: 16 | - path: WDBXEditor.zip 17 | name: WDBXEditor 18 | --------------------------------------------------------------------------------