Template
*
This commit is contained in:
+192
@@ -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<ShFileRecord> fileRecords = new List<ShFileRecord>();
|
||||
for(int i = 0; i < 2074; ++i) {
|
||||
fileRecords.Add(LibCD.Serialization.StreamReader.ReadStruct<ShFileRecord>(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");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Dependencies\libcd.net\Src\LibCD.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
Reference in New Issue
Block a user