diff --git a/CreateXDF/Program.cs b/CreateXDF/Program.cs index 1d62c82..e29c66d 100644 --- a/CreateXDF/Program.cs +++ b/CreateXDF/Program.cs @@ -25,7 +25,7 @@ namespace CreateXDF 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, + 0x73, 0x73, 0x69, 0x6F, 0x6E, 0x0A, 0x0A, 0xC0, 0x6E, 0xEF, 0xDD, 0x5F, 0x00, 0x00, 0x00, 0x00, 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, @@ -39,14 +39,51 @@ namespace CreateXDF 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[] minibpb = { 0xEB, 0x4F, 0x90, 0x58, 0x44, 0x46, 0x76, 0x31, 0x2E, 0x33, 0x69, 0x00, 0x02, 0x01, 0x01, 0x00, + 0x02, 0x10, 0x00, 0x08, 0x00, 0xF9, 0x01, 0x00, 0x08, 0x00, 0x01, 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, 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, 0xDB, 0xCD, 0xDA, 0x55, 0x00, 0x00, 0x00, 0x00, + 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; + static readonly byte[] miniFatEntry = { 0xF9, 0xFF, 0xFF, 0x03, 0x40, 0x00, 0xFF, 0x2F }; const ushort rootEntries = 224; const byte formatByte = 0xF6; + const string miniMessage = "This is a XDF disk created with CreateXDF.\n\r" + + "You need to use IBM's XDF.COM driver to access its contents."; + public static void Main(string[] args) { string volname = "NEW XDF IMG"; @@ -55,6 +92,7 @@ namespace CreateXDF ushort spt = 0; byte unk_sector_num = 0x0B; DateTime creation = DateTime.Now; + ushort fatSectors = 11; if((args.Length != 2 && args.Length != 3) || (args[0] != "-3" && args[0] != "-5")) { @@ -75,13 +113,15 @@ namespace CreateXDF spt = 23; mediaDescriptor = 0xF0; unk_sector_num = 0x0B; + fatSectors = 11; } else if (args[0] == "-5") { spt = 19; mediaDescriptor = 0xF9; unk_sector_num = 0x09; - } + fatSectors = 9; + } sectors = (ushort)(80 * 2 * spt); FileStream fs = new FileStream(args[1], FileMode.CreateNew, FileAccess.ReadWrite); @@ -150,13 +190,28 @@ namespace CreateXDF tmp = Encoding.ASCII.GetBytes(volname.ToUpper()); fs.Write(tmp, 0, tmp.Length >= 11 ? 11 : tmp.Length); - // Write FATs + // Write FAT 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; + // Write miniBPB + fs.Write(minibpb, 0, 512); + fs.Seek(-512, SeekOrigin.Current); + fs.Seek(0x26, SeekOrigin.Current); + fs.WriteByte(0x29); + fs.Write(serial, 0, 4); + tmp = Encoding.ASCII.GetBytes(volname.ToUpper()); + fs.Write(tmp, 0, tmp.Length >= 11 ? 11 : tmp.Length); + fs.Seek(512 - 0x36, SeekOrigin.Current); + + // Write miniFAT + byte[] miniFat = new byte[512]; + Array.Copy(miniFat, 0, miniFatEntry, 0, miniFatEntry.Length); + fs.Write(miniFat, 0, 512); + fs.Write(miniFat, 0, 512); + + // 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; @@ -166,41 +221,63 @@ namespace CreateXDF byte[] cdate_b = BitConverter.GetBytes(cdate); byte[] ctime_b = BitConverter.GetBytes(ctime); + byte[] dirEntry = new byte[32]; // Volume label for (int i = 0; i < 11; i++) - rootDir[i] = 0x20; + dirEntry[i] = 0x20; tmp = Encoding.ASCII.GetBytes(volname.ToUpper()); - Array.Copy(tmp, 0, rootDir, 0, tmp.Length >= 11 ? 11 : tmp.Length); + Array.Copy(tmp, 0, dirEntry, 0, tmp.Length >= 11 ? 11 : tmp.Length); // Attributes - rootDir[11] = 8; + dirEntry[11] = 8; // Case information - rootDir[12] = 0; + dirEntry[12] = 0; // Creation time milliseconds. This is DR-DOS so don't use. - rootDir[13] = 0; + dirEntry[13] = 0; // Creation time - Array.Copy(ctime_b, 0, rootDir, 14, 2); + Array.Copy(ctime_b, 0, dirEntry, 14, 2); // Creation date - Array.Copy(cdate_b, 0, rootDir, 16, 2); + Array.Copy(cdate_b, 0, dirEntry, 16, 2); // Last access date. From Windows 95 so don't use. - rootDir[18] = 0; - rootDir[19] = 0; + dirEntry[18] = 0; + dirEntry[19] = 0; // Extended attributes handler - rootDir[20] = 0; - rootDir[21] = 0; + dirEntry[20] = 0; + dirEntry[21] = 0; // Last written time - Array.Copy(ctime_b, 0, rootDir, 22, 2); + Array.Copy(ctime_b, 0, dirEntry, 22, 2); // Last written date - Array.Copy(cdate_b, 0, rootDir, 24, 2); + Array.Copy(cdate_b, 0, dirEntry, 24, 2); // Starting cluster - rootDir[26] = 0; - rootDir[27] = 0; + dirEntry[26] = 0; + dirEntry[27] = 0; // Size - rootDir[28] = 0; - rootDir[29] = 0; - rootDir[30] = 0; - rootDir[31] = 0; + dirEntry[28] = 0; + dirEntry[29] = 0; + dirEntry[30] = 0; + dirEntry[31] = 0; - fs.Write(rootDir, 0, rootDir.Length); + Array.Copy(dirEntry, 0, rootDir, 0, 32); + + // Write mini root + byte[] miniDir = new byte[512]; + Array.Copy(dirEntry, 0, miniDir, 0, 32); + tmp = Encoding.ASCII.GetBytes("README TXT"); + Array.Copy(tmp, 0, dirEntry, 0, 11); + dirEntry[11] = 1; + dirEntry[26] = 2; + int messageLen = Encoding.ASCII.GetBytes(miniMessage).Length; + tmp = BitConverter.GetBytes((uint)(messageLen < 512 ? messageLen : 512)); + Array.Copy(tmp, 0, dirEntry, 28, 4); + Array.Copy(dirEntry, 0, miniDir, 32, 32); + fs.Write(miniDir, 0, 512); + + // Write message file + tmp = Encoding.ASCII.GetBytes(miniMessage); + fs.Write(tmp, 0, tmp.Length >= 512 ? 512 : tmp.Length); + + // Write root + fs.Seek(spt * 512, SeekOrigin.Begin); + fs.Write(rootDir, 0, rootDir.Length); ushort remainingSectors = (ushort)(sectors - (fatSectors * 2 + rootDir.Length / 512 + 1)); tmp = new byte[512]; @@ -213,6 +290,8 @@ namespace CreateXDF byte[] checksum = BitConverter.GetBytes(xdfcopy_verify_checksum(fs, unk_sector_num)); fs.Seek(0x13C, SeekOrigin.Begin); fs.Write(checksum, 0, 4); + fs.Seek((fatSectors + 1) * 512 + 0x13C, SeekOrigin.Begin); + fs.Write(checksum, 0, 4); fs.Close(); }