First commit:

- BW/BW2 save file detection
- Checksum verifier (no DLC yet)
- Checksum updater (no DLC yet)
- Block dumper /injector (only first save)
- Block dumper decryption is hardcoded for entralink forest block right now

Todo:
- Add BW offset tables
- Add per-block decryption with known decrypted blocks
- Add boxes to specify encryption address, size and seed address (for use without editing source)
- Add BW2 DLC blocks
- Insert hidden grotto and swarm form
- A lot more...
This commit is contained in:
suloku
2016-03-02 18:06:05 +01:00
parent 1309cef254
commit f367b7f976
14 changed files with 1416 additions and 0 deletions

18
BW_tool.sln Normal file
View File

@@ -0,0 +1,18 @@

Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
# SharpDevelop 5.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BW_tool", "BW_tool\BW_tool.csproj", "{41ABAC38-D34B-489D-A450-3E9FADD07419}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{41ABAC38-D34B-489D-A450-3E9FADD07419}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{41ABAC38-D34B-489D-A450-3E9FADD07419}.Debug|Any CPU.Build.0 = Debug|Any CPU
{41ABAC38-D34B-489D-A450-3E9FADD07419}.Release|Any CPU.ActiveCfg = Release|Any CPU
{41ABAC38-D34B-489D-A450-3E9FADD07419}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal

82
BW_tool/BW_tool.csproj Normal file
View File

@@ -0,0 +1,82 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build">
<PropertyGroup>
<ProjectGuid>{41ABAC38-D34B-489D-A450-3E9FADD07419}</ProjectGuid>
<ProjectTypeGuids>{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<OutputType>WinExe</OutputType>
<RootNamespace>BW_tool</RootNamespace>
<AssemblyName>BW_tool</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<AppDesignerFolder>Properties</AppDesignerFolder>
</PropertyGroup>
<PropertyGroup Condition=" '$(Platform)' == 'AnyCPU' ">
<PlatformTarget>x86</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<OutputPath>bin\Debug\</OutputPath>
<DebugSymbols>True</DebugSymbols>
<DebugType>Full</DebugType>
<Optimize>False</Optimize>
<CheckForOverflowUnderflow>True</CheckForOverflowUnderflow>
<DefineConstants>DEBUG;TRACE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<OutputPath>bin\Release\</OutputPath>
<DebugSymbols>False</DebugSymbols>
<DebugType>None</DebugType>
<Optimize>True</Optimize>
<CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
<DefineConstants>TRACE</DefineConstants>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.CSharp">
<RequiredTargetFramework>4.0</RequiredTargetFramework>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data" />
<Reference Include="System.Data.DataSetExtensions">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
<Reference Include="System.Xml.Linq">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Dumper.cs" />
<Compile Include="Dumper.Designer.cs">
<DependentUpon>Dumper.cs</DependentUpon>
</Compile>
<Compile Include="MainForm.cs" />
<Compile Include="MainForm.Designer.cs">
<DependentUpon>MainForm.cs</DependentUpon>
</Compile>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SAV\FileIO.cs" />
<Compile Include="SAV\SAV5.cs" />
<Compile Include="SAV\PKX5.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
</ItemGroup>
<ItemGroup>
<Folder Include="SAV" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Dumper.resx">
<DependentUpon>Dumper.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="MainForm.resx">
<DependentUpon>MainForm.cs</DependentUpon>
</EmbeddedResource>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

193
BW_tool/Dumper.Designer.cs generated Normal file
View File

@@ -0,0 +1,193 @@
/*
* Created by SharpDevelop.
* User: suloku
* Date: 02/03/2016
* Time: 0:19
*
* To change this template use Tools | Options | Coding | Edit Standard Headers.
*/
namespace BW_tool
{
partial class Dumper
{
/// <summary>
/// Designer variable used to keep track of non-visual components.
/// </summary>
private System.ComponentModel.IContainer components = null;
private System.Windows.Forms.Button dump_but;
private System.Windows.Forms.Button inject_but;
private System.Windows.Forms.Button dump_dec_but;
private System.Windows.Forms.Button inject_crypt_but;
private System.Windows.Forms.ComboBox selectedblock;
/// <summary>
/// Disposes resources used by the form.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing) {
if (components != null) {
components.Dispose();
}
}
base.Dispose(disposing);
}
/// <summary>
/// This method is required for Windows Forms designer support.
/// Do not change the method contents inside the source code editor. The Forms designer might
/// not be able to load this method if it was changed manually.
/// </summary>
private void InitializeComponent()
{
this.dump_but = new System.Windows.Forms.Button();
this.inject_but = new System.Windows.Forms.Button();
this.dump_dec_but = new System.Windows.Forms.Button();
this.inject_crypt_but = new System.Windows.Forms.Button();
this.selectedblock = new System.Windows.Forms.ComboBox();
this.SuspendLayout();
//
// dump_but
//
this.dump_but.Location = new System.Drawing.Point(254, 39);
this.dump_but.Name = "dump_but";
this.dump_but.Size = new System.Drawing.Size(75, 23);
this.dump_but.TabIndex = 1;
this.dump_but.Text = "Dump";
this.dump_but.UseVisualStyleBackColor = true;
this.dump_but.Click += new System.EventHandler(this.Dump_butClick);
//
// inject_but
//
this.inject_but.Location = new System.Drawing.Point(353, 39);
this.inject_but.Name = "inject_but";
this.inject_but.Size = new System.Drawing.Size(75, 23);
this.inject_but.TabIndex = 2;
this.inject_but.Text = "Inject";
this.inject_but.UseVisualStyleBackColor = true;
this.inject_but.Click += new System.EventHandler(this.Inject_butClick);
//
// dump_dec_but
//
this.dump_dec_but.Location = new System.Drawing.Point(204, 68);
this.dump_dec_but.Name = "dump_dec_but";
this.dump_dec_but.Size = new System.Drawing.Size(125, 23);
this.dump_dec_but.TabIndex = 3;
this.dump_dec_but.Text = "Dump and Decrypt";
this.dump_dec_but.UseVisualStyleBackColor = true;
this.dump_dec_but.Click += new System.EventHandler(this.Dump_dec_butClick);
//
// inject_crypt_but
//
this.inject_crypt_but.Location = new System.Drawing.Point(353, 68);
this.inject_crypt_but.Name = "inject_crypt_but";
this.inject_crypt_but.Size = new System.Drawing.Size(125, 23);
this.inject_crypt_but.TabIndex = 4;
this.inject_crypt_but.Text = "Inject and Recrypt";
this.inject_crypt_but.UseVisualStyleBackColor = true;
this.inject_crypt_but.Click += new System.EventHandler(this.Inject_crypt_butClick);
//
// selectedblock
//
this.selectedblock.FormattingEnabled = true;
this.selectedblock.Items.AddRange(new object[] {
"00 - Box Names",
"01 - Box 1",
"02 - Box 2",
"03 - Box 3",
"04 - Box 4",
"05 - Box 5",
"06 - Box 6",
"07 - Box 7",
"08 - Box 8",
"09 - Box 9",
"10 - Box 10",
"11 - Box 11",
"12 - Box 12",
"13 - Box 13",
"14 - Box 14",
"15 - Box 15",
"16 - Box 16",
"17 - Box 17",
"18 - Box 18",
"19 - Box 19",
"20 - Box 20",
"21 - Box 21",
"22 - Box 22",
"23 - Box 23",
"24 - Box 24",
"25 - Inventory",
"26 - Party Pokemon",
"27 - Trainer Data",
"28 - Trainer Position",
"29 - Unity Tower and survey stuff",
"30 - Pal Pad Player Data (30d)",
"31 - Pal Pad Friend Data",
"32 - C-Gear",
"33 - Card Signature Block & ????",
"34 - Mystery Gift",
"35 - Dream World Stuff (Catalog)",
"36 - Chatter",
"37 - Adventure data http://projectpokemon.org/forums/showthread.php?24589-B2W2-Ge" +
"neral-ROM-Info&p=167300&viewfull=1#post167300",
"38 - Trainer Card Records",
"39 - Unknown",
"40 - (40d)",
"41 - Unknown",
"42 - Contains flags and references for downloaded data (Musical)",
"43 - Fused Reshiram/Zekrom Storage",
"44 - Unknown",
"45 - Const Data Block and Event Flag Block (0x35E is the split)",
"46 - Unknown",
"47 - Tournament Block",
"48 - Unknown",
"49 - Battle Box Block",
"50 - Daycare Block (50d)",
"51 - Strength Boulder Status Block",
"52 - Badge Flags, Money, Trainer Sayings",
"53 - Entralink (Level & Powers etc)",
"54 - Pokedex",
"55 - Swarm and other overworld info - 2C - swarm, 2D - repel steps, 2E repel type" +
"",
"56 - Unknown",
"57 - Unknown",
"58 - Unknown",
"59 - Online Records",
"60 - Entralink Forest - encrypted (60d)",
"61 - Unknown",
"62 - Unknown",
"63 - Unknown",
"64 - Unknown",
"65 - Unknown",
"66 - Hollow/Rival Block",
"67 - Join Avenue Block",
"68 - Medal data",
"69 - Key-related data",
"70 - Unknown (70d)",
"71 - Unknown",
"72 - Unknown",
"73 - Checksum Block (73d)"});
this.selectedblock.Location = new System.Drawing.Point(12, 12);
this.selectedblock.MaxDropDownItems = 10;
this.selectedblock.Name = "selectedblock";
this.selectedblock.Size = new System.Drawing.Size(692, 21);
this.selectedblock.TabIndex = 5;
//
// Dumper
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(716, 103);
this.Controls.Add(this.selectedblock);
this.Controls.Add(this.inject_crypt_but);
this.Controls.Add(this.dump_dec_but);
this.Controls.Add(this.inject_but);
this.Controls.Add(this.dump_but);
this.Name = "Dumper";
this.Text = "Block Dumper&Injector";
this.ResumeLayout(false);
}
}
}

86
BW_tool/Dumper.cs Normal file
View File

@@ -0,0 +1,86 @@
/*
* Created by SharpDevelop.
* User: suloku
* Date: 02/03/2016
* Time: 0:19
*
* To change this template use Tools | Options | Coding | Edit Standard Headers.
*/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
namespace BW_tool
{
/// <summary>
/// Description of Form1.
/// </summary>
public partial class Dumper : Form
{
public Dumper()
{
//
// The InitializeComponent() call is required for Windows Forms designer support.
//
InitializeComponent();
selectedblock.SelectedIndex = 0;
selectedblock.DropDownStyle = ComboBoxStyle.DropDownList;
//
// TODO: Add constructor code after the InitializeComponent() call.
//
}
public string binaryfilter = "Binary data|*.bin|All Files (*.*)|*.*";
void Dump_butClick(object sender, EventArgs e)
{
SaveFileDialog saveFD = new SaveFileDialog();
//saveFD.InitialDirectory = "c:\\";
saveFD.Filter = binaryfilter;
if (saveFD.ShowDialog() == DialogResult.OK)
{
System.IO.FileStream saveFile;
saveFile = new FileStream(saveFD.FileName, FileMode.Create);
//Write file
saveFile.Write(MainForm.save.getBlock((int)selectedblock.SelectedIndex), 0, MainForm.save.getBlockLength((int)selectedblock.SelectedIndex));
saveFile.Close();
MessageBox.Show("File Saved.", "Save file");
}
}
public byte[] injectfile;
void Inject_butClick(object sender, EventArgs e)
{
string path = null;
FileIO.load_file(ref injectfile, ref path, binaryfilter);
MainForm.save.setBlock( injectfile, (int)selectedblock.SelectedIndex);
//MessageBox.Show(injectfile.Length.ToString());
}
void Dump_dec_butClick(object sender, EventArgs e)
{
SaveFileDialog saveFD = new SaveFileDialog();
//saveFD.InitialDirectory = "c:\\";
saveFD.Filter = binaryfilter;
if (saveFD.ShowDialog() == DialogResult.OK)
{
System.IO.FileStream saveFile;
saveFile = new FileStream(saveFD.FileName, FileMode.Create);
//Write file
saveFile.Write(MainForm.save.getBlockDec((int)selectedblock.SelectedIndex), 0, MainForm.save.getBlockLength((int)selectedblock.SelectedIndex));
saveFile.Close();
MessageBox.Show("File Saved.", "Save file");
}
}
void Inject_crypt_butClick(object sender, EventArgs e)
{
string path = null;
FileIO.load_file(ref injectfile, ref path, binaryfilter);
MainForm.save.setBlockCrypt( injectfile, (int)selectedblock.SelectedIndex);
//MessageBox.Show(injectfile.Length.ToString());
}
}
}

120
BW_tool/Dumper.resx Normal file
View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

125
BW_tool/MainForm.Designer.cs generated Normal file
View File

@@ -0,0 +1,125 @@
/*
* Created by SharpDevelop.
* User: suloku
* Date: 01/03/2016
* Time: 20:03
*
* To change this template use Tools | Options | Coding | Edit Standard Headers.
*/
namespace BW_tool
{
partial class MainForm
{
/// <summary>
/// Designer variable used to keep track of non-visual components.
/// </summary>
private System.ComponentModel.IContainer components = null;
private System.Windows.Forms.Button loadsave_but;
private System.Windows.Forms.TextBox savegamename;
private System.Windows.Forms.Button save_but;
private System.Windows.Forms.Label versiontext;
private System.Windows.Forms.Button dumper_but;
private System.Windows.Forms.Button chk_but;
/// <summary>
/// Disposes resources used by the form.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing) {
if (components != null) {
components.Dispose();
}
}
base.Dispose(disposing);
}
/// <summary>
/// This method is required for Windows Forms designer support.
/// Do not change the method contents inside the source code editor. The Forms designer might
/// not be able to load this method if it was changed manually.
/// </summary>
private void InitializeComponent()
{
this.loadsave_but = new System.Windows.Forms.Button();
this.savegamename = new System.Windows.Forms.TextBox();
this.save_but = new System.Windows.Forms.Button();
this.versiontext = new System.Windows.Forms.Label();
this.dumper_but = new System.Windows.Forms.Button();
this.chk_but = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// loadsave_but
//
this.loadsave_but.Location = new System.Drawing.Point(12, 12);
this.loadsave_but.Name = "loadsave_but";
this.loadsave_but.Size = new System.Drawing.Size(132, 23);
this.loadsave_but.TabIndex = 0;
this.loadsave_but.Text = "Load Savegame";
this.loadsave_but.UseVisualStyleBackColor = true;
this.loadsave_but.Click += new System.EventHandler(this.Loadsave_butClick);
//
// savegamename
//
this.savegamename.Location = new System.Drawing.Point(12, 41);
this.savegamename.Name = "savegamename";
this.savegamename.Size = new System.Drawing.Size(484, 20);
this.savegamename.TabIndex = 1;
//
// save_but
//
this.save_but.Location = new System.Drawing.Point(421, 12);
this.save_but.Name = "save_but";
this.save_but.Size = new System.Drawing.Size(75, 23);
this.save_but.TabIndex = 2;
this.save_but.Text = "Save";
this.save_but.UseVisualStyleBackColor = true;
this.save_but.Click += new System.EventHandler(this.Save_butClick);
//
// versiontext
//
this.versiontext.Location = new System.Drawing.Point(150, 17);
this.versiontext.Name = "versiontext";
this.versiontext.Size = new System.Drawing.Size(100, 18);
this.versiontext.TabIndex = 3;
//
// dumper_but
//
this.dumper_but.Location = new System.Drawing.Point(12, 80);
this.dumper_but.Name = "dumper_but";
this.dumper_but.Size = new System.Drawing.Size(92, 23);
this.dumper_but.TabIndex = 4;
this.dumper_but.Text = "Block dumper";
this.dumper_but.UseVisualStyleBackColor = true;
this.dumper_but.Click += new System.EventHandler(this.Dumper_butClick);
//
// chk_but
//
this.chk_but.Location = new System.Drawing.Point(316, 12);
this.chk_but.Name = "chk_but";
this.chk_but.Size = new System.Drawing.Size(99, 23);
this.chk_but.TabIndex = 5;
this.chk_but.Text = "Verify Checksums";
this.chk_but.UseVisualStyleBackColor = true;
this.chk_but.Click += new System.EventHandler(this.Chk_butClick);
//
// MainForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(503, 119);
this.Controls.Add(this.chk_but);
this.Controls.Add(this.dumper_but);
this.Controls.Add(this.versiontext);
this.Controls.Add(this.save_but);
this.Controls.Add(this.savegamename);
this.Controls.Add(this.loadsave_but);
this.Name = "MainForm";
this.Text = "Gen V save tool";
this.ResumeLayout(false);
this.PerformLayout();
}
}
}

74
BW_tool/MainForm.cs Normal file
View File

@@ -0,0 +1,74 @@
/*
* Created by SharpDevelop.
* User: suloku
* Date: 01/03/2016
* Time: 20:03
*
* To change this template use Tools | Options | Coding | Edit Standard Headers.
*/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
namespace BW_tool
{
/// <summary>
/// Description of MainForm.
/// </summary>
public partial class MainForm : Form
{
public MainForm()
{
//
// The InitializeComponent() call is required for Windows Forms designer support.
//
InitializeComponent();
//
// TODO: Add constructor code after the InitializeComponent() call.
//
}
public string dsfilter = "NDS save data|*.sav;*.dsv|All Files (*.*)|*.*";
public byte[] savebuffer;
public static SAV5 save;
void Loadsave_butClick(object sender, EventArgs e)
{
versiontext.Text = "";
string path = null;
if(FileIO.load_file(ref savebuffer, ref path, dsfilter) == 1)
{
savegamename.Text = path;
save = new SAV5(savebuffer);
if (save.B2W2) versiontext.Text = "Black/White 2";
else if (save.BW) versiontext.Text = "Black/White 1";
else versiontext.Text = "Invalid file";
}else{
savegamename.Text = "";
}
}
void Save_butClick(object sender, EventArgs e)
{
if (save.Edited)
FileIO.save_data(save.Data);
else MessageBox.Show("Save has not been edited");
}
void Dumper_butClick(object sender, EventArgs e)
{
Form dumper = new Dumper();
dumper.Show();
}
void Chk_butClick(object sender, EventArgs e)
{
save.chkCheck();
}
}
}

120
BW_tool/MainForm.resx Normal file
View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

31
BW_tool/Program.cs Normal file
View File

@@ -0,0 +1,31 @@
/*
* Created by SharpDevelop.
* User: suloku
* Date: 01/03/2016
* Time: 20:03
*
* To change this template use Tools | Options | Coding | Edit Standard Headers.
*/
using System;
using System.Windows.Forms;
namespace BW_tool
{
/// <summary>
/// Class with program entry point.
/// </summary>
internal sealed class Program
{
/// <summary>
/// Program entry point.
/// </summary>
[STAThread]
private static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
}
}

View File

@@ -0,0 +1,31 @@
#region Using directives
using System;
using System.Reflection;
using System.Runtime.InteropServices;
#endregion
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("BW_tool")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("BW_tool")]
[assembly: AssemblyCopyright("Copyright 2016")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// This sets the default COM visibility of types in the assembly to invisible.
// If you need to expose a type to COM, use [ComVisible(true)] on that type.
[assembly: ComVisible(false)]
// The assembly version has following format :
//
// Major.Minor.Build.Revision
//
// You can specify all the values or you can use the default the Revision and
// Build Numbers by using the '*' as shown below:
[assembly: AssemblyVersion("1.0.*")]

98
BW_tool/SAV/FileIO.cs Normal file
View File

@@ -0,0 +1,98 @@
/*
* Created by SharpDevelop.
* User: suloku
* Date: 02/03/2016
* Time: 8:01
*
* To change this template use Tools | Options | Coding | Edit Standard Headers.
*/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
namespace BW_tool
{
/// <summary>
/// Description of FileIO.
/// </summary>
public class FileIO
{
/// <summary>
/// Reads data into a complete array, throwing an EndOfStreamException
/// if the stream runs out of data first, or if an IOException
/// naturally occurs.
/// </summary>
/// <param name="stream">The stream to read data from</param>
/// <param name="data">The array to read bytes into. The array
/// will be completely filled from the stream, so an appropriate
/// size must be given.</param>
private static void ReadWholeArray (Stream stream, ref byte[] data)
{
int offset=0;
int remaining = data.Length;
while (remaining > 0)
{
int read = stream.Read(data, offset, remaining);
if (read <= 0)
throw new EndOfStreamException
(String.Format("End of stream reached with {0} bytes left to read", remaining));
remaining -= read;
offset += read;
}
}
private static void _read_data(ref byte [] buffer, string path)
{
System.IO.FileStream saveFile;
saveFile = new FileStream(path, FileMode.Open);
if (saveFile.Length < 1){
MessageBox.Show("Invalid file length", "Error");
return;
}
buffer = new byte[saveFile.Length];
//MessageBox.Show(buffer.Length.ToString());
ReadWholeArray(saveFile, ref buffer);
saveFile.Close();
return;
}
public static int load_file(ref byte[] buffer, ref string path, string filter)
{
OpenFileDialog openFD = new OpenFileDialog();
//openFD.InitialDirectory = "c:\\";
openFD.Filter = filter;
if (openFD.ShowDialog() == DialogResult.OK)
{
#region filename
path = openFD.FileName;
//MessageBox.Show(path.ToString());
#endregion
_read_data(ref buffer, path);
return 1;
}else{
return -1;
}
}
public static void save_data(byte[] buffer)
{ //if (savegamename.Text.Length < 1) return;
if (buffer == null) return;
SaveFileDialog saveFD = new SaveFileDialog();
//saveFD.InitialDirectory = "c:\\";
saveFD.Filter = "NDS save data|*.sav;*.dsv|All Files (*.*)|*.*";
if (saveFD.ShowDialog() == DialogResult.OK)
{
System.IO.FileStream saveFile;
saveFile = new FileStream(saveFD.FileName, FileMode.Create);
//Write file
saveFile.Write(buffer, 0, buffer.Length);
saveFile.Close();
MessageBox.Show("File Saved.", "Save file");
}
}
}
}

103
BW_tool/SAV/PKX5.cs Normal file
View File

@@ -0,0 +1,103 @@
using System;
using System.Drawing;
using System.Drawing.Text;
using System.Linq;
namespace BW_tool
{
public class PKX5
{
// C# PKX Function Library
// No WinForm object related code, only to calculate information.
// May require re-referencing to main form for string array referencing.
// Relies on Util for some common operations.
/* // Data
internal static uint LCRNG(uint seed)
{
const uint a = 0x41C64E6D;
const uint c = 0x00006073;
return seed * a + c;
}
internal static uint LCRNG(ref uint seed)
{
const uint a = 0x41C64E6D;
const uint c = 0x00006073;
return seed = seed * a + c;
}
internal static byte[] decryptArray(byte[] ekx, int start_offset, int length, int seed_offset)
{
byte[] pkx = (byte[])ekx.Clone();
uint pv = BitConverter.ToUInt32(pkx, seed_offset);
uint sv = (pv >> 0xD & 0x1F) % 24;
uint seed = pv;
// Decrypt Blocks with RNG Seed
for (int i = start_offset; i < length-4; i += 2)
BitConverter.GetBytes((ushort)(BitConverter.ToUInt16(pkx, i) ^ LCRNG(ref seed) >> 16)).CopyTo(pkx, i);
return pkx;
}
*/
internal static UInt32 LCRNG(UInt32 seed)
// --------------------------------------------------
{
UInt32 a = 0x41c64e6d;
UInt32 c = 0x00006073;
return (UInt32)(((UInt64)seed * (UInt64)a + (UInt64)c)&0x00000000FFFFFFFF);
}
internal static byte[] cryptoArray(byte[] ekx, int start_offset, int length, int seed_offset)
// --------------------------------------------------
{
byte[] buffer_dec = (byte[])ekx.Clone();
UInt32 pv = BitConverter.ToUInt32(buffer_dec, seed_offset);
byte sv = (byte)((((pv & 0x3e000) >> 0xd) % 24)&0x000000FF);
UInt32 seed = pv;
UInt16 tmp;
for (Int32 i = start_offset; i < length-4; i += 0x2)
{
tmp = BitConverter.ToUInt16(buffer_dec, i);
seed = LCRNG(seed);
tmp ^= (UInt16)((seed >> 16)&0x0000FFFF);
Array.Copy(BitConverter.GetBytes(tmp), 0, buffer_dec, i, 2);
}
return buffer_dec;
}
// SAV Manipulation
/// <summary>Calculates the CRC16-CCITT checksum over an input byte array.</summary>
/// <param name="chunk">Input byte array</param>
/// <returns>Checksum</returns>
//adapted from Gocario's PHBank (www.github.com/gocario/phbank)
internal static ushort ccitt16(byte[] data)
// --------------------------------------------------
{
int len = data.Length;
UInt16 crc = 0xFFFF;
for (UInt32 i = 0; i < len; i++)
{
crc ^= ((UInt16)((data[i] << 8)&0x0000FFFF));
for (UInt32 j = 0; j < 0x8; j++)
{
if ((crc & 0x8000) > 0)
crc = (UInt16)(((UInt16)((crc << 1)&0x0000FFFF ) ^ 0x1021) &0x0000FFFF);
else
crc <<= 1;
}
}
return crc;
}
}
}

329
BW_tool/SAV/SAV5.cs Normal file
View File

@@ -0,0 +1,329 @@
//Base file from kaphotic's pkhex
using System;
using System.Linq;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
namespace BW_tool
{
public class BlockInfo
{
public int Offset;
public int Length;
public int ID;
public int updtcnt;
public int Checksum;
public bool encrypted;
public int seed;
}
public class SAV5 : PKX5
{
private static int[] BlockTableBW2 =
{0x00000, 0x00400, 0x01400, 0x02400, 0x03400, 0x04400, 0x05400, //6
0x06400, 0x07400, 0x08400, 0x09400, 0x0A400, 0x0B400, 0x0C400, //13
0x0D400, 0x0E400, 0x0F400, 0x10400, 0x11400, 0x12400, 0x13400, //20
0x14400, 0x15400, 0x16400, 0x17400, 0x18400, 0x18E00, 0x19400, //27
0x19500, 0x19600, 0x1AA00, 0x1B200, 0x1C000, 0x1C100, 0x1C800, //34
0x1D300, 0x1D500, 0x1D900, 0x1DA00, 0x1DC00, 0x1DD00, 0x1E200, //41
0x1F700, 0x1FA00, 0x1FB00, 0x1FF00, 0x20400, 0x20500, 0x20800, //48
0x20900, 0x20D00, 0x20F00, 0x21100, 0x21200, 0x21400, 0x21900, //55
0x21A00, 0x21B00, 0x21D00, 0x22900, 0x22A00, 0x23300, 0x23600, //62
0x23700, 0x23800, 0x23A00, 0x23B00, 0x23C00, 0x25300, 0x25800, //69
0x25900, 0x25A00, 0x25E00, 0x25F00}; //73
private static int[] BlockTableLengthBW2 =
{0x3E0, 0xFF0, 0xFF0, 0xFF0, 0xFF0, 0xFF0, 0xFF0, //6
0xFF0, 0xFF0, 0xFF0, 0xFF0, 0xFF0, 0xFF0, 0xFF0, //13
0xFF0, 0xFF0, 0xFF0, 0xFF0, 0xFF0, 0xFF0, 0xFF0, //20
0xFF0, 0xFF0, 0xFF0, 0xFF0, 0x9EC, 0X534, 0xB0, //27
0xA8, 0x1338, 0x7C4, 0xD54, 0X94, 0x658, 0xA94, //34
0x1AC, 0x3EC, 0x5C, 0x1E0, 0xA8, 0x460, 0x1400, //41
0x2A4, 0xE0, 0x34C, 0x4E0, 0xF8, 0x2FC, 0x94, //48
0x35C, 0x1D4, 0x1E0, 0xF0, 0x1B4, 0x4DC, 0x34, //55
0X3C, 0x1AC, 0xB90, 0xAC, 0x850, 0x284, 0x10, //62
0xA8, 0x16C, 0x80, 0xFC, 0x16A8, 0x498, 0x60, //69
0xFC, 0x3E4, 0xF0, 0x94};
internal const int SIZERAW = 0x80000; // 512KB
internal const int SIZE1 = 0x24000; // B/W
internal const int SIZE2 = 0x26000; // B2/W2
// Global Settings
// Save Data Attributes
public byte[] Data;
public bool Edited;
public readonly bool Exportable;
public readonly byte[] BAK;
public string FileName, FilePath;
public BlockInfo[] blocks = new BlockInfo[74];
public bool B2W2;
public bool BW;
public SAV5(byte[] data)
{
Data = (byte[])(data ?? new byte[SIZERAW]).Clone();
BAK = (byte[])Data.Clone();
Exportable = !Data.SequenceEqual(new byte[Data.Length]);
// Get Version
// Validate Checksum over the Checksum Block to find BW or B2W2
ushort chk2 = BitConverter.ToUInt16(Data, SIZE2 - 0x100 + 0x94 + 0xE);
ushort actual2 = ccitt16(Data.Skip(SIZE2 - 0x100).Take(0x94).ToArray());
B2W2 = chk2 == actual2;
ushort chk1 = BitConverter.ToUInt16(Data, SIZE1 - 0x100 + 0x8C + 0xE);
ushort actual1 = ccitt16(Data.Skip(SIZE1 - 0x100).Take(0x8C).ToArray());
BW = chk1 == actual1;
if (!BW && !B2W2 && data != null){
Data = null; // Invalid/Not G5 Save File
}else if (B2W2)
{
//Build blockinfos
int i;
for (i=0;i<74;i++)
{
blocks[i] = new BlockInfo();
blocks[i].Offset=BlockTableBW2[i];
blocks[i].Length=BlockTableLengthBW2[i];
blocks[i].ID= i;
blocks[i].updtcnt=blocks[i].Offset+blocks[i].Length;
if (i != 73)
{
blocks[i].Checksum=blocks[i].Offset+blocks[i].Length+2;
}
else
{
blocks[i].Checksum=0x25FA2;
}
blocks[i].encrypted=false;
blocks[i].seed=blocks[i].Offset+blocks[i].Length-4;
}
// Different Offsets for different games.
BattleBox = B2W2 ? 0x20A00 : 0x20900;
}
}
private const int Box = 0x400;
private const int Party = 0x18E00;
private readonly int BattleBox;
private const int Trainer = 0x19400;
private const int Wondercard = 0x1C800;
private const int wcSeed = 0x1D290;
public byte[] getData(int Offset, int Length)
{
return Data.Skip(Offset).Take(Length).ToArray();
}
public byte[] getBlock(int index)
{
if (B2W2)
{
if (index <73)
{
return Data.Skip(blocks[index].Offset).Take(blocks[index+1].Offset-blocks[index].Offset).ToArray();
}
else if (index == 73)
{
return Data.Skip(blocks[index].Offset).Take(SIZE2-blocks[index].Offset).ToArray();
}
else return null;
}
else return null;
}
public byte[] getBlockDec(int index)
{
byte[] decrypt = new byte[getBlockLength(index)];
if (B2W2)
{
if (index <73)
{
//MessageBox.Show(decrypt.Length.ToString());
//MessageBox.Show((blocks[index].Length-4).ToString());
decrypt = PKX5.cryptoArray(Data.Skip(blocks[index].Offset).Take(blocks[index+1].Offset-blocks[index].Offset).ToArray(), 0, blocks[index].Length, blocks[index].Length-4);
//MessageBox.Show((blocks[index].Length-4).ToString());
return decrypt;
}
else if (index == 73)
{
return Data.Skip(blocks[index].Offset).Take(SIZE2-blocks[index].Offset).ToArray();
}
else return null;
}
else return null;
}
public int getBlockLength(int index)
{
if (B2W2){
if (index < 73)
return blocks[index+1].Offset-blocks[index].Offset;
else if (index == 73)
return SIZE2-blocks[index].Offset;
else return -1;
}
else return -1;
}
public void setBlock(byte[] input, int index)
{
if (getBlockLength(index) != input.Length)
{
MessageBox.Show("Block has invalid size!");
return;
}
if (B2W2)
{
if (index <74)
{
//Recalculate checksum before applying to savedata
ushort crc = ccitt16(input.Take(blocks[index].Length).ToArray());
if (crc != BitConverter.ToUInt16(input, blocks[index].Checksum-blocks[index].Offset) )
{
Array.Copy(BitConverter.GetBytes(crc), 0, input, blocks[index].Checksum-blocks[index].Offset, 2);
MessageBox.Show("Block's checksum updated");
}else
{
MessageBox.Show("Checksum doesn't need update");
}
input.CopyTo(Data, blocks[index].Offset);
input.CopyTo(Data, blocks[index].Offset+SIZE2);
Edited = true;
}
else return;
}
else return;
}
public void setBlockCrypt(byte[] input, int index)
{
if (getBlockLength(index) != input.Length)
{
MessageBox.Show("Block has invalid size!");
return;
}
if (B2W2)
{
if (index <74)
{
//Recalculate checksum before applying to savedata
ushort crc = ccitt16(input.Take(blocks[index].Length).ToArray());
if (crc != BitConverter.ToUInt16(input, blocks[index].Checksum-blocks[index].Offset) )
{
Array.Copy(BitConverter.GetBytes(crc), 0, input, blocks[index].Checksum-blocks[index].Offset, 2);
MessageBox.Show("Block's checksum updated");
}else
{
MessageBox.Show("Checksum doesn't need update");
}
input.CopyTo(Data, blocks[index].Offset);
input.CopyTo(Data, blocks[index].Offset+SIZE2);
Edited = true;
}
else return;
}
else return;
}
public void setData(byte[] input, int Offset)
{
input.CopyTo(Data, Offset);
Edited = true;
}
public void chkCheck()
{
int i = 0;
string badblocks;
badblocks = "Found bad checksums in MAIN save at blocks: ";
bool badcheck = false;
if (B2W2)
{
//Main save checksums
for(i=0; i<74; i++)
{
ushort crc = ccitt16(Data.Skip(blocks[i].Offset).Take(blocks[i].Length).ToArray());
if ( crc != BitConverter.ToUInt16(Data, blocks[i].Checksum) )
{
//Array.Copy(BitConverter.GetBytes(crc), 0, input, blocks[index].Checksum-blocks[index].Offset, 2);
//MessageBox.Show("Block's checksum is wrong " + i.ToString());
if (!badcheck)
{
badcheck = true;
badblocks = badblocks + i.ToString();
}else
{
badblocks = badblocks + ", " + i.ToString();
}
}
else
{
//MessageBox.Show("Checksum doesn't need update " + i.ToString());
}
}
if(badcheck)
MessageBox.Show(badblocks);
else
MessageBox.Show("All 74 checksums OK in MAIN save");
//Backup save checksums
badcheck = false;
badblocks = "Found bad checksums in BACKUP save at blocks: ";
for(i=0; i<74; i++)
{
ushort crc = ccitt16(Data.Skip(blocks[i].Offset+SIZE2).Take(blocks[i].Length).ToArray());
if ( crc != BitConverter.ToUInt16(Data, blocks[i].Checksum+SIZE2) )
{
//Array.Copy(BitConverter.GetBytes(crc), 0, input, blocks[index].Checksum-blocks[index].Offset, 2);
//MessageBox.Show("Block's checksum is wrong " + i.ToString());
if (!badcheck)
{
badcheck = true;
badblocks = badblocks + i.ToString();
}else
{
badblocks = badblocks + ", " + i.ToString();
}
}
else
{
//MessageBox.Show("Checksum doesn't need update " + i.ToString());
}
}
if(badcheck)
MessageBox.Show(badblocks);
else
MessageBox.Show("All 74 checksums OK in BACKUP save");
return;
}
else if (BW)
{
MessageBox.Show("Not yet implemented for BW 1");
}
else
{
MessageBox.Show("Invalid file");
return;
}
}
}
}

6
BW_tool/app.config Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0" />
</startup>
</configuration>