commit 1260390353cc09a3fdb730ef91f04d8a57af0f22 Author: l-proger Date: Tue May 13 01:00:58 2025 +0300 * diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..33d8b0f --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +/Src/.vs +/Src/bin +/Src/obj +/TestData diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..6389581 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "Dependencies/libcd.net"] + path = Dependencies/libcd.net + url = https://github.com/L-proger/libcd.net.git + branch = main diff --git a/Dependencies/libcd.net b/Dependencies/libcd.net new file mode 160000 index 0000000..581aae6 --- /dev/null +++ b/Dependencies/libcd.net @@ -0,0 +1 @@ +Subproject commit 581aae64a6007380afb91cfe577a236bc44eacaf diff --git a/README.md b/README.md new file mode 100644 index 0000000..ba65fc5 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# SilentHillTools + diff --git a/Src/Program.cs b/Src/Program.cs new file mode 100644 index 0000000..ba7dc64 --- /dev/null +++ b/Src/Program.cs @@ -0,0 +1,192 @@ +using System.Runtime.CompilerServices; +using System.Xml.Linq; + +//File table parsing algorithm: https://github.com/mbystryantsev/consolgames-tools/blob/master/game-specific/Silent%20Hill/FilesExtractor/Silent.cpp + +namespace LibCD { + class App { + static string CalledFileDir([CallerFilePath] string path = null) { + return System.IO.Path.GetDirectoryName(path); + } + + static string TestDataDir { + get { + return Path.Combine(CalledFileDir(), "..", "TestData"); + + } + } + + static string ImageFilePath { + get { return Path.Combine(TestDataDir, "Image.bin"); } + } + + + static void PrintFileSystem(ISO9660.FileSystem.Directory dir, string fullPath) { + fullPath += dir.Name; + Console.WriteLine(fullPath); + + foreach (var file in dir.Files) { + Console.WriteLine($"{fullPath}/{file.Name} | LBA: {file.LBA} SIZE: {file.Size}"); + } + + foreach (var childDir in dir.Directories) { + PrintFileSystem(childDir, fullPath + "/"); + } + } + + + public static ISO9660.FileSystem.File? FindFile(ISO9660.FileSystem fs, string name) { + var dir = fs.RootDirectory; + foreach (var file in dir.Files) { + if (file.Name.StartsWith(name)) { + return file; + } + } + return null; + } + + + struct ShFileRecord { + public uint b1; + public uint b2; + public uint b3; + + public uint StartSector { + get { + return b1 & 0x7ffff; + } + } + public uint ChunkCount { + get { + return b1 >> 19; + } + } + + public uint DirectoryIndex { + get { + return b2 & 0xf; + } + } + + + public uint Name0 { + get { + return (b2 >> 4) & 0xffffff; + } + } + public uint Dummy { + get { + return (b2 >> 28); + } + } + + public uint Name1 { + get { + return b3 & 0xffffff; + } + } + + public uint ExtensionIndex { + get { + return b3 >> 24; + } + } + + + public string Name { + get { + string result = ""; + uint[] values = new uint[] { Name0, Name1 }; + + for (int j = 0; j < 2; j++) { + uint v = values[j]; + for (int i = 0; i < 4 && v != 0; i++) { + byte c = (byte)((v & 0x3F) + 0x20); + result += (char)c; + v >>= 6; + } + } + return result; + } + } + + public string Directory { + get { + return DefaultDirectoryStruct[DirectoryIndex]; + } + } + + public string Extension { + get { + return DefaultExtensions[DirectoryIndex]; + } + } + + public string Path { + get { + return System.IO.Path.Combine(Directory, $"{Name}{Extension}"); + } + } + + public uint Size { + get { + return ChunkCount * 0x100; + } + } + } + + static string[] DefaultExtensions = new string[16] + { + ".TIM", ".VAB", ".BIN", ".DMS", + ".ANM", ".PLM", ".IPD", ".ILM", + ".TMD", ".DAT", ".KDT", ".CMP", + ".TXT", "", "", "" + }; + + static string[] DefaultDirectoryStruct = new string[16] + { + "1ST", "ANIM", "BG", "CHARA", + "ITEM", "MISC", "SND", "TEST", + "TIM", "VIN", "XA", "", + "", "", "", "" + }; + + public static void Main() { + Console.WriteLine(ImageFilePath); + + var fs = new ISO9660.FileSystem(File.OpenRead(ImageFilePath)); + var xaDiscLabel = fs.PrimaryVolumeDescriptor.GetXADiscLabel(); + + var exeFile = FindFile(fs, "SLUS_007.07"); + var dataFile = FindFile(fs, "SILENT"); + + var exeFileStream = exeFile.OpenRead(fs.SectorStream); + exeFileStream.Seek(0xB91C, SeekOrigin.Current); + + List fileRecords = new List(); + for(int i = 0; i < 2074; ++i) { + fileRecords.Add(LibCD.Serialization.StreamReader.ReadStruct(exeFileStream)); + } + + string exportDirectory = @"E:\CdContent"; + foreach (var file in fileRecords) { + fs.SectorStream.SeekToSector(file.StartSector); + var srcFileStream = new CdByteStream(fs.SectorStream); + byte[] data = srcFileStream.Read((int)file.Size); + + string outPath = Path.Combine(exportDirectory, file.Path); + string outDir = Path.GetDirectoryName(outPath); + Directory.CreateDirectory(outDir); + + File.WriteAllBytes(outPath, data); + + + Console.WriteLine($"{file.Path}"); + } + + + // + Console.WriteLine("Done"); + } + } +} \ No newline at end of file diff --git a/Src/SilentHillTools.csproj b/Src/SilentHillTools.csproj new file mode 100644 index 0000000..7efdca4 --- /dev/null +++ b/Src/SilentHillTools.csproj @@ -0,0 +1,14 @@ + + + + Exe + net8.0 + enable + enable + + + + + + +