Initial commit.

This commit is contained in:
2017-08-28 19:30:41 +01:00
parent 01be6feb4d
commit 3517f45004
4 changed files with 357 additions and 0 deletions

17
CreateXDF.sln Normal file
View File

@@ -0,0 +1,17 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2012
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CreateXDF", "CreateXDF\CreateXDF.csproj", "{00C12FC7-49DD-4291-8757-D6CD349641B8}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x86 = Debug|x86
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{00C12FC7-49DD-4291-8757-D6CD349641B8}.Debug|x86.ActiveCfg = Debug|x86
{00C12FC7-49DD-4291-8757-D6CD349641B8}.Debug|x86.Build.0 = Debug|x86
{00C12FC7-49DD-4291-8757-D6CD349641B8}.Release|x86.ActiveCfg = Release|x86
{00C12FC7-49DD-4291-8757-D6CD349641B8}.Release|x86.Build.0 = Release|x86
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<ProjectGuid>{00C12FC7-49DD-4291-8757-D6CD349641B8}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>CreateXDF</RootNamespace>
<AssemblyName>CreateXDF</AssemblyName>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ExternalConsole>true</ExternalConsole>
<PlatformTarget>x86</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<Optimize>true</Optimize>
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ExternalConsole>true</ExternalConsole>
<PlatformTarget>x86</PlatformTarget>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>

275
CreateXDF/Program.cs Normal file
View File

@@ -0,0 +1,275 @@
using System;
using System.IO;
using System.Text;
namespace CreateXDF
{
class MainClass
{
static readonly byte[] bpb = { 0xEB, 0x4F, 0x90, 0x49, 0x42, 0x4D, 0x20, 0x32, 0x30, 0x2E, 0x30, 0x00, 0x02, 0x01, 0x01, 0x00,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x46, 0x41, 0x54, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00,
0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0xFA, 0x33, 0xDB, 0x8E, 0xD3, 0xBC, 0xFF, 0x7B, 0xFB, 0xBA,
0xC0, 0xFA, 0x29, 0xC0, 0x8E, 0xD0, 0xBC, 0x00, 0x7C, 0xFB, 0x0E, 0x1F, 0xBE, 0x40, 0x7D, 0x8A,
0x04, 0x08, 0xC0, 0x74, 0x0D, 0x56, 0x1E, 0xB4, 0x0E, 0xB7, 0x00, 0xCD, 0x10, 0x1F, 0x5E, 0x46,
0xEB, 0xED, 0xB4, 0x00, 0xCD, 0x16, 0xCD, 0x19, 0xB9, 0x0B, 0x00, 0xF3, 0x00, 0x29, 0x0D, 0xB6,
0x58, 0x44, 0x46, 0x20, 0x76, 0x31, 0x2E, 0x31, 0x61, 0x20, 0x28, 0x63, 0x29, 0x20, 0x31, 0x39,
0x39, 0x33, 0x2C, 0x20, 0x31, 0x39, 0x39, 0x34, 0x20, 0x2D, 0x2D, 0x20, 0x42, 0x61, 0x63, 0x6B,
0x75, 0x70, 0x20, 0x54, 0x65, 0x63, 0x68, 0x6E, 0x6F, 0x6C, 0x6F, 0x67, 0x69, 0x65, 0x73, 0x2C,
0x20, 0x49, 0x6E, 0x63, 0x2E, 0x2C, 0x20, 0x54, 0x61, 0x6D, 0x70, 0x61, 0x20, 0x46, 0x4C, 0x0A,
0x20, 0x50, 0x61, 0x74, 0x65, 0x6E, 0x74, 0x28, 0x73, 0x29, 0x20, 0x50, 0x65, 0x6E, 0x64, 0x69,
0x6E, 0x67, 0x20, 0x2D, 0x2D, 0x20, 0x49, 0x6E, 0x76, 0x65, 0x6E, 0x74, 0x6F, 0x72, 0x3A, 0x20,
0x52, 0x6F, 0x67, 0x65, 0x72, 0x20, 0x44, 0x2E, 0x20, 0x49, 0x76, 0x65, 0x79, 0x0A, 0x41, 0x6C,
0x6C, 0x20, 0x72, 0x69, 0x67, 0x68, 0x74, 0x73, 0x20, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65,
0x64, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x77, 0x69, 0x64, 0x65, 0x0A, 0x44, 0x75, 0x70, 0x6C,
0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x70, 0x72, 0x6F, 0x68, 0x69, 0x62, 0x69, 0x74,
0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x6F, 0x75, 0x74, 0x20, 0x70, 0x65, 0x72, 0x6D, 0x69,
0x73, 0x73, 0x69, 0x6F, 0x6E, 0x0A, 0x0A, 0xC0, 0x6E, 0xEF, 0xDD, 0x5F, 0xA5, 0xDA, 0xB1, 0xF7,
0x4F, 0x53, 0x2F, 0x32, 0x20, 0x21, 0x21, 0x20, 0x53, 0x59, 0x53, 0x30, 0x31, 0x34, 0x37, 0x35,
0x0D, 0x0A, 0x4F, 0x53, 0x2F, 0x32, 0x20, 0x21, 0x21, 0x20, 0x53, 0x59, 0x53, 0x30, 0x32, 0x30,
0x32, 0x37, 0x0D, 0x0A, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x50, 0x61, 0x74, 0x65, 0x6E,
0x74, 0x28, 0x73, 0x29, 0x20, 0x50, 0x65, 0x6E, 0x64, 0x69, 0x6E, 0x67, 0x0D, 0x0A, 0x0D, 0x0A,
0x4E, 0x6F, 0x6E, 0x2D, 0x42, 0x6F, 0x6F, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x20, 0x58, 0x44, 0x46,
0x20, 0x44, 0x61, 0x74, 0x61, 0x20, 0x44, 0x69, 0x73, 0x6B, 0x0D, 0x0A, 0x49, 0x6E, 0x73, 0x65,
0x72, 0x74, 0x20, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6D, 0x20, 0x64, 0x69, 0x73, 0x6B, 0x20, 0x61,
0x6E, 0x64, 0x20, 0x70, 0x72, 0x65, 0x73, 0x73, 0x20, 0x61, 0x6E, 0x79, 0x20, 0x6B, 0x65, 0x79,
0x0D, 0x0A, 0x00, 0x53, 0x2F, 0x32, 0x20, 0x21, 0x21, 0x20, 0x53, 0x59, 0x53, 0x30, 0x32, 0x30,
0x32, 0x37, 0x0D, 0x0A, 0x00, 0x4F, 0x53, 0x32, 0x42, 0x4F, 0x4F, 0x54, 0x20, 0x20, 0x20, 0x20,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xAA };
static readonly byte[] fatid = { 0xF9, 0xFF, 0xFF };
const ushort fatSectors = 11;
const ushort rootEntries = 224;
const byte formatByte = 0xF6;
public static void Main(string[] args)
{
string volname = "NEW XDF IMG";
ushort sectors = 0;
byte mediaDescriptor = 0xF0;
ushort spt = 0;
byte unk_sector_num = 0x0B;
DateTime creation = DateTime.Now;
if((args.Length != 2 && args.Length != 3) || (args[0] != "-3" && args[0] != "-5"))
{
Console.WriteLine("CreateXDF - Creates an empty XDF disk image usable by XDFCOPY or emulators.");
Console.WriteLine("Usage:");
Console.WriteLine();
Console.WriteLine("CreateXDF -3/-5 image.xdf <volumename>");
Console.WriteLine("\t-3 creates a 3.5\" XDF disk image");
Console.WriteLine("\t-5 creates a 5.25\" XDF disk image");
return;
}
if (args.Length == 3)
volname = args[2];
if (args[0] == "-3")
{
spt = 23;
mediaDescriptor = 0xF0;
unk_sector_num = 0x0B;
}
else if (args[0] == "-5")
{
spt = 19;
mediaDescriptor = 0xF9;
unk_sector_num = 0x09;
}
sectors = (ushort)(80 * 2 * spt);
FileStream fs = new FileStream(args[1], FileMode.CreateNew, FileAccess.ReadWrite);
byte[] fat = new byte[fatSectors * 512];
Array.Copy(fatid, 0, fat, 0, 3);
byte[] rootDir = new byte[rootEntries * 32];
Random rand = new Random();
byte[] serial = new byte[4];
rand.NextBytes(serial);
byte[] tmp;
fs.Write(bpb, 0, 512);
fs.Seek(0, SeekOrigin.Begin);
// This is intentionally done step by step :p
// Skip jump
fs.Seek(3, SeekOrigin.Current);
// Skip OEM name
fs.Seek(8, SeekOrigin.Current);
// Bytes per sector
tmp = BitConverter.GetBytes((ushort)512);
fs.Write(tmp, 0, 2);
// Sectors per cluster
fs.WriteByte(1);
// Reserved sectors between BPB and FAT
tmp = BitConverter.GetBytes((ushort)1);
fs.Write(tmp, 0, 2);
// Number of FATs
fs.WriteByte(2);
// Entries in root directory
tmp = BitConverter.GetBytes(rootEntries);
fs.Write(tmp, 0, 2);
// Sectors in volume
tmp = BitConverter.GetBytes(sectors);
fs.Write(tmp, 0, 2);
// Media descriptor
fs.WriteByte(mediaDescriptor);
// Sectors per FAT
tmp = BitConverter.GetBytes(fatSectors);
fs.Write(tmp, 0, 2);
// Sectors per track
tmp = BitConverter.GetBytes(spt);
fs.Write(tmp, 0, 2);
// Heads
tmp = BitConverter.GetBytes((ushort)2);
fs.Write(tmp, 0, 2);
// Hidden sectors before BPB
tmp = BitConverter.GetBytes((uint)0);
fs.Write(tmp, 0, 4);
// Sectors in volume if > 65535
tmp = BitConverter.GetBytes((uint)0);
fs.Write(tmp, 0, 4);
// Drive numer
fs.WriteByte(0);
// Volume flags
fs.WriteByte(0);
// EBPB signature
fs.WriteByte(0x29);
// Serial number
fs.Write(serial, 0, 4);
// Volume label
tmp = Encoding.ASCII.GetBytes(volname.ToUpper());
fs.Write(tmp, 0, tmp.Length >= 11 ? 11 : tmp.Length);
// Write FATs
fs.Seek(512, SeekOrigin.Begin);
fs.Write(fat, 0, fat.Length);
fs.Write(fat, 0, fat.Length);
// Create directory entry
ushort ctime = 0, cdate = 0;
cdate += (ushort)(((creation.Year - 1980) << 9) & 0xFE00);
cdate += (ushort)((creation.Month << 5) & 0x1E0);
cdate += (ushort)creation.Day;
ctime += (ushort)((creation.Hour << 11) & 0xF800);
ctime += (ushort)((creation.Minute << 5) & 0x7E0);
ctime += (ushort)(creation.Second / 2);
byte[] cdate_b = BitConverter.GetBytes(cdate);
byte[] ctime_b = BitConverter.GetBytes(ctime);
// Volume label
for (int i = 0; i < 11; i++)
rootDir[i] = 0x20;
tmp = Encoding.ASCII.GetBytes(volname.ToUpper());
Array.Copy(tmp, 0, rootDir, 0, tmp.Length >= 11 ? 11 : tmp.Length);
// Attributes
rootDir[11] = 8;
// Case information
rootDir[12] = 0;
// Creation time milliseconds. This is DR-DOS so don't use.
rootDir[13] = 0;
// Creation time
Array.Copy(ctime_b, 0, rootDir, 14, 2);
// Creation date
Array.Copy(cdate_b, 0, rootDir, 16, 2);
// Last access date. From Windows 95 so don't use.
rootDir[18] = 0;
rootDir[19] = 0;
// Extended attributes handler
rootDir[20] = 0;
rootDir[21] = 0;
// Last written time
Array.Copy(ctime_b, 0, rootDir, 22, 2);
// Last written date
Array.Copy(cdate_b, 0, rootDir, 24, 2);
// Starting cluster
rootDir[26] = 0;
rootDir[27] = 0;
// Size
rootDir[28] = 0;
rootDir[29] = 0;
rootDir[30] = 0;
rootDir[31] = 0;
fs.Write(rootDir, 0, rootDir.Length);
ushort remainingSectors = (ushort)(sectors - (fatSectors * 2 + rootDir.Length / 512 + 1));
tmp = new byte[512];
for (int i = 0; i < 512; i++)
tmp[i] = formatByte;
for (ushort i = 0; i < remainingSectors; i++)
fs.Write(tmp, 0, 512);
// Write checksum
byte[] checksum = BitConverter.GetBytes(xdfcopy_verify_checksum(fs, unk_sector_num));
fs.Seek(0x13C, SeekOrigin.Begin);
fs.Write(checksum, 0, 4);
fs.Close();
}
// XDFCOPY algorithm from OBattler's xdfsum.c
static void xdfcopy_read_file(FileStream fs, uint start, uint len, ref byte[] buf)
{
fs.Seek(start << 9, SeekOrigin.Begin);
buf = new byte[len << 9];
fs.Read(buf, 0, buf.Length);
}
static uint xdfcopy_checksum(ref byte[] buf, ushort len)
{
ushort loc2 = 0;
ushort checksum = 0xABDC;
ushort i = 0;
for (i = 0; i < len; i++)
{
loc2 = buf[(buf[i] * 0x13) % len];
checksum += (ushort)((loc2 >> 5) + ((loc2 & 0x1F) << 4));
}
return checksum;
}
static uint xdfcopy_verify_checksum(FileStream fs, uint unk_sector_num)
{
ushort dx;
short i;
uint checksum;
byte[] buf = null;
byte[] pbuf = new byte[512];
fs.Seek(0x80, SeekOrigin.Begin);
fs.Read(pbuf, 0, 0xB6);
pbuf[0xB6] = 0;
fs.Seek(0, SeekOrigin.Begin);
checksum = 0x12345678;
xdfcopy_read_file(fs, 1, 5, ref buf); // sub_72 probably just reads Y sectors from sector X onwards in the image
checksum = (checksum << 1) + xdfcopy_checksum(ref buf, 0x0A00);
xdfcopy_read_file(fs, (unk_sector_num << 1) + 1, 5, ref buf); // from sector 25 onwards for 3.5" 2HD
checksum = (checksum << 1) + xdfcopy_checksum(ref buf, 0x0A00);
xdfcopy_read_file(fs, (unk_sector_num << 1) + 6, 5, ref buf); // from sector 30 onwards for 3.5" 2HD
checksum = (checksum << 1) + xdfcopy_checksum(ref buf, 0x0A00);
for (i = 0; i < 0xB6; i++)
{
dx = (ushort)(((unk_sector_num << 1) + 0x15) + pbuf[i] + (checksum & 0x7ff));
xdfcopy_read_file(fs, dx, 1, ref buf);
checksum = (checksum << 1) + xdfcopy_checksum(ref buf, 0x0200);
}
return checksum;
}
}
}

View File

@@ -0,0 +1,26 @@
using System.Reflection;
using System.Runtime.CompilerServices;
// Information about this assembly is defined by the following attributes.
// Change them to the values specific to your project.
[assembly: AssemblyTitle("CreateXDF")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Claunia.com")]
[assembly: AssemblyProduct("")]
[assembly: AssemblyCopyright("Copyright © Claunia.com")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
// The form "{Major}.{Minor}.*" will automatically update the build and revision,
// and "{Major}.{Minor}.{Build}.*" will update just the revision.
[assembly: AssemblyVersion("1.0.*")]
// The following attributes are used to specify the signing key for the assembly,
// if desired. See the Mono documentation for more information about signing.
//[assembly: AssemblyDelaySign(false)]
//[assembly: AssemblyKeyFile("")]