-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
385 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<OutputType>Exe</OutputType> | ||
<TargetFramework>net7.0</TargetFramework> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<Nullable>enable</Nullable> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<ProjectReference Include="..\DmfLib\DmfLib.csproj" /> | ||
</ItemGroup> | ||
|
||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
using SaibanDataLib; | ||
using System.Linq; | ||
using System.Numerics; | ||
using System.Text; | ||
using System.Text.Encodings.Web; | ||
public partial class Program | ||
{ | ||
/* | ||
First 3 bytes: DMF (Identifier of filetype) | ||
At position 4, 4 bytes: Number of files (Int 16) | ||
At position 8, file entries begin, see below | ||
*/ | ||
|
||
|
||
/* File Entry | ||
* 4 Bytes : (Length of FilePath) (Integer 16) | ||
* (Length Of FilePath) Bytes: (File Path) (String) | ||
* 4 Bytes : File Offset Within archive (Integer 32) | ||
* 4 Bytes : File Size (Int 16 / ushort ) // STILL WORKING ON THIS PART! | ||
* */ | ||
|
||
/* | ||
* After file Entries raw uncompressed filedata | ||
*/ | ||
|
||
public static void Main(string[] args) | ||
{ | ||
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); | ||
Console.ForegroundColor = ConsoleColor.Gray; | ||
Console.OutputEncoding = Encoding.Unicode; //Encoding.GetEncoding("Shift-JIS"); | ||
Console.InputEncoding = Encoding.Unicode; | ||
|
||
|
||
|
||
if (args.Length < 1) | ||
{ | ||
Console.WriteLine("Enter or drag and drop the file you want to extract\nOR\nEnter or drag and drop the folder you want to repack"); | ||
} | ||
string selectedFile = (args.Length > 0) ? args[0] : Console.ReadLine().Replace("\"", string.Empty); | ||
|
||
string outDirectory = Directory.GetParent(selectedFile).FullName; | ||
|
||
if (Directory.Exists(selectedFile)) | ||
{ | ||
Console.ForegroundColor = ConsoleColor.Yellow; | ||
Console.WriteLine("Packing..."); | ||
Dmf.Pack(selectedFile); | ||
Console.ForegroundColor = ConsoleColor.Green; | ||
Console.WriteLine("Packed!"); | ||
Main(new string[] { }); | ||
return; | ||
} | ||
Dmf DmfFileInstance = new Dmf(selectedFile); | ||
|
||
if (!DmfFileInstance.IsDMF()) // Check if it's an actual DMF file | ||
{ | ||
Console.ForegroundColor = ConsoleColor.Red; | ||
Console.WriteLine("Provided File is not a DMF File!"); | ||
Main(new string[] { }); return; | ||
} | ||
|
||
Console.ForegroundColor = ConsoleColor.Yellow; | ||
Console.WriteLine("Extracting Files..."); | ||
|
||
DmfFileInstance.ExtractAllFiles(outDirectory + selectedFile.Substring(selectedFile.LastIndexOf("\\")).Replace(".dat", "") + "_extracted\\"); | ||
DmfFileInstance.Dispose(); | ||
DmfFileInstance = null; | ||
Console.ForegroundColor = ConsoleColor.Green; | ||
Console.WriteLine("Extracted Files!"); | ||
|
||
Main(new string[] { }); | ||
|
||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,243 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
|
||
namespace SaibanDataLib | ||
{ | ||
// ALl this code genuinely sucks I'm sorry :( | ||
// | ||
public class Dmf | ||
{ | ||
public static string FileSignature = "DMF "; // Identifier | ||
public Stream dataStream; | ||
|
||
public List<string> filePaths = new List<string>(); // Should Probably have this as a class but.... | ||
private List<int> fileSizes = new List<int>(); | ||
private List<int> filePositions = new List<int>(); | ||
|
||
public int NumberOfFiles; | ||
public static bool IsDMF(Stream datStream) // Checks if this is a legitimate DMF file | ||
{ | ||
datStream.Position = 0; | ||
|
||
byte[] bufferName = new byte[FileSignature.Length]; // Attempt to get magic bytes | ||
|
||
datStream.Read(bufferName); | ||
|
||
string ApparantName = System.Text.Encoding.GetEncoding("Shift-JIS").GetString(bufferName); | ||
|
||
if (FileSignature != ApparantName) // Check if the string of the identifier bytes is equivalent to the identifier of the data file | ||
{ | ||
return false; | ||
} | ||
return true; | ||
} | ||
public bool IsDMF() | ||
{ | ||
return IsDMF(this.dataStream); | ||
} | ||
private byte[] GetFileData(int i) // Get the actual file Data | ||
{ | ||
int fileOffset = filePositions[i]; | ||
string filePath = filePaths[i]; | ||
//int fileSize = fileSizes[i]; this is unreliable! | ||
|
||
// Since I can't find the filesize properlly within the file's entries, I'm just going "screw it" and using the differences of fileOffsets | ||
// I'm sorry for the ineligant solution D: | ||
|
||
// (If not at the end of list Get next Item otherwise get end of stream) Subtract with the fileoffset | ||
int fileSize = ((i < fileSizes.Count - 1) ? filePositions[i + 1] : (int)dataStream.Length) - fileOffset; | ||
|
||
|
||
byte[] fileData = new byte[fileSize]; | ||
|
||
dataStream.Position = fileOffset; // Travel to it's offset within the file | ||
dataStream.Read(fileData); // Read the data into the buffer | ||
|
||
return fileData; | ||
} | ||
public byte[] GetFileData(string path) | ||
{ | ||
return GetFileData(filePaths.IndexOf(path)); | ||
} | ||
public void ExtractFile(int i, string outDirectory) | ||
{ | ||
string filePath = filePaths[i]; | ||
byte[] fileData = GetFileData(i); | ||
filePath = filePath.Replace("/", "\\"); | ||
string newPath = outDirectory + filePath; | ||
Directory.CreateDirectory(Directory.GetParent(newPath).ToString()); | ||
if (fileData.Length == 0) | ||
{ | ||
File.Create(newPath); | ||
return; | ||
} | ||
File.WriteAllBytes(newPath, fileData); | ||
} | ||
public void ExtractAllFiles(string outDirectory) // Todo: Clean this stuff up! | ||
{ | ||
ReadFileMetaData(); | ||
|
||
if (Directory.Exists(outDirectory)) | ||
{ | ||
Directory.Delete(outDirectory, true); | ||
} | ||
|
||
for (int i = 0; i < filePaths.Count; i++) | ||
{ | ||
ExtractFile(i, outDirectory); | ||
} | ||
} | ||
public void ReadFileMetaData() // Get lists of all File Paths, Sizes and Locations | ||
{ | ||
if (NumberOfFiles == null) // We rely on number of files! | ||
{ | ||
ReadHeader(); | ||
} | ||
|
||
|
||
filePaths = new List<string>(); | ||
filePositions = new List<int>(); | ||
fileSizes = new List<int>(); | ||
|
||
|
||
dataStream.Position = 8; // Start at First file Entry | ||
// TODO: Fix file sizes | ||
|
||
while (filePaths.Count < NumberOfFiles) | ||
{ | ||
int fileNameLength = dataStream.ReadByte(); | ||
|
||
|
||
byte[] fileNameBuffer = new byte[fileNameLength]; // Read the actual string | ||
dataStream.Position += 3; // This +3 is needed to include the file extension (for some reason), if it's removed everything gets broken! | ||
dataStream.Read(fileNameBuffer); | ||
dataStream.Position -= 3; | ||
string filePath = System.Text.Encoding.GetEncoding("Shift-JIS").GetString(fileNameBuffer); // Convert FilePath string into Shift-JIS (Japanese character set) | ||
filePaths.Add(filePath); | ||
|
||
|
||
byte[] fileLocationBuffer = new byte[4]; // Location of the File's raw data in the Archive | ||
dataStream.Position += 3; | ||
dataStream.Read(fileLocationBuffer); | ||
int fileLocation = (int)BitConverter.ToInt32(fileLocationBuffer); | ||
filePositions.Add(fileLocation); | ||
|
||
byte[] tempBuffer = new byte[4]; // The file size (Completely BROKEN, I just ignore this and use the differences in file positions as a temp fix cause I dont understand this at all!) | ||
dataStream.Read(tempBuffer); | ||
int fileSize = BitConverter.ToUInt16(tempBuffer); | ||
fileSizes.Add(fileSize); | ||
} | ||
} | ||
public static void Pack(string folder) // temp, This is super screwed but I'll fix it later... Maybe (It does repack it as a 1:1 perfect replica of the original file and the games reads it perfectly so maybe not) | ||
{ | ||
List<string> tempfilePaths = new List<string>(); | ||
List<int> tempfileSizes = new List<int>(); | ||
List<byte[]> tempfileData = new List<byte[]>(); | ||
List<long> tempFileLocations = new List<long>(); | ||
List<long> tempFileMetaLocations = new List<long>(); | ||
FileStream tempDMFFile = new FileStream(folder + ".dat", FileMode.Create); | ||
EnumerationOptions enumuratorOptions = new EnumerationOptions(); | ||
enumuratorOptions.RecurseSubdirectories = true; | ||
tempfilePaths = Directory.EnumerateFiles(folder, "*", enumuratorOptions).ToList(); | ||
|
||
|
||
|
||
tempDMFFile.Position = 0; | ||
byte[] identifier = new byte[4]{ 68,77,70,32}; | ||
tempDMFFile.Write(identifier); | ||
tempDMFFile.Position = 4; | ||
tempDMFFile.Write(BitConverter.GetBytes(tempfilePaths.Count)); | ||
tempDMFFile.Position = 8; | ||
for (int i =0; i < tempfilePaths.Count; i++) | ||
{ | ||
|
||
int fileLocation = 0; | ||
|
||
|
||
string newPath = tempfilePaths[i].Replace(folder + "\\", "").Replace("\\", "/"); | ||
string oldPath = tempfilePaths[i]; | ||
tempfilePaths[i] = newPath; | ||
|
||
tempfileData.Add(File.ReadAllBytes(oldPath)); | ||
|
||
byte[] PathAsBytes = Encoding.GetEncoding("Shift-JIS").GetBytes(newPath.Substring(0, newPath.Length - 4)); | ||
|
||
string extension = newPath.Substring(newPath.Length - 4); | ||
extension = extension.ToLowerInvariant(); | ||
byte[] ExtensionAsBytes = Encoding.ASCII.GetBytes(extension); | ||
|
||
|
||
tempDMFFile.Write(BitConverter.GetBytes(PathAsBytes.Length + ExtensionAsBytes.Length)); | ||
|
||
foreach (byte c in PathAsBytes) | ||
{ | ||
tempDMFFile.WriteByte(c); | ||
} | ||
|
||
foreach (byte c in ExtensionAsBytes) | ||
{ | ||
tempDMFFile.WriteByte(((byte)c)); | ||
} | ||
|
||
|
||
int fileSize = tempfileData[i].Length; | ||
tempFileMetaLocations.Add(tempDMFFile.Position); | ||
tempDMFFile.Write(BitConverter.GetBytes(fileLocation)); | ||
tempDMFFile.Write(BitConverter.GetBytes(fileSize)); | ||
|
||
|
||
} | ||
|
||
for (int i =0; i < tempfileData.Count; i++) | ||
{ | ||
long fileLoc = tempDMFFile.Position; | ||
tempFileLocations.Add(tempDMFFile.Position); | ||
int fileSize = tempfileData[i].Length; | ||
tempDMFFile.Write(tempfileData[i]); | ||
|
||
long currentLoc = tempDMFFile.Position; | ||
|
||
tempDMFFile.Position = tempFileMetaLocations[i]; | ||
tempDMFFile.Write(BitConverter.GetBytes((int)fileLoc)); | ||
tempDMFFile.Write(BitConverter.GetBytes(fileSize)); | ||
tempDMFFile.Position = currentLoc; | ||
} | ||
|
||
tempDMFFile.Dispose(); | ||
tempDMFFile.Close(); | ||
|
||
|
||
} | ||
public void ReadHeader() | ||
{ | ||
if (!IsDMF()) | ||
{ | ||
return; | ||
} | ||
dataStream.Position = 4; // Skip the DMF identifier etc | ||
byte[] lengthOfMetaBuffer = new byte[4]; | ||
dataStream.Read(lengthOfMetaBuffer); | ||
NumberOfFiles = BitConverter.ToInt16(lengthOfMetaBuffer); | ||
ReadFileMetaData(); | ||
} | ||
public void Dispose() | ||
{ | ||
dataStream.Dispose(); | ||
dataStream.Close(); | ||
|
||
} | ||
public Dmf(Stream stream) | ||
{ | ||
dataStream= stream; | ||
ReadHeader(); | ||
} | ||
public Dmf(string path) | ||
{ | ||
dataStream = new FileStream(path, FileMode.Open, FileAccess.Read); | ||
ReadHeader(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<TargetFramework>net7.0</TargetFramework> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<Nullable>enable</Nullable> | ||
</PropertyGroup> | ||
|
||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<OutputType>Exe</OutputType> | ||
<TargetFramework>net7.0</TargetFramework> | ||
<ImplicitUsings>enable</ImplicitUsings> | ||
<Nullable>enable</Nullable> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="System.Text.Encoding.CodePages" Version="8.0.0" /> | ||
</ItemGroup> | ||
|
||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
|
||
Microsoft Visual Studio Solution File, Format Version 12.00 | ||
# Visual Studio Version 17 | ||
VisualStudioVersion = 17.4.33403.182 | ||
MinimumVisualStudioVersion = 10.0.40219.1 | ||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DmfExtract", "DmfExtract\DmfExtract.csproj", "{6350B34C-69BF-43E0-BD6D-28C999788F3C}" | ||
EndProject | ||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DmfLib", "DmfLib\DmfLib.csproj", "{63916B97-6E2B-41E7-87AB-BEFFE564E633}" | ||
EndProject | ||
Global | ||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||
Debug|Any CPU = Debug|Any CPU | ||
Release|Any CPU = Release|Any CPU | ||
EndGlobalSection | ||
GlobalSection(ProjectConfigurationPlatforms) = postSolution | ||
{6350B34C-69BF-43E0-BD6D-28C999788F3C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
{6350B34C-69BF-43E0-BD6D-28C999788F3C}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
{6350B34C-69BF-43E0-BD6D-28C999788F3C}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
{6350B34C-69BF-43E0-BD6D-28C999788F3C}.Release|Any CPU.Build.0 = Release|Any CPU | ||
{63916B97-6E2B-41E7-87AB-BEFFE564E633}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
{63916B97-6E2B-41E7-87AB-BEFFE564E633}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
{63916B97-6E2B-41E7-87AB-BEFFE564E633}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
{63916B97-6E2B-41E7-87AB-BEFFE564E633}.Release|Any CPU.Build.0 = Release|Any CPU | ||
EndGlobalSection | ||
GlobalSection(SolutionProperties) = preSolution | ||
HideSolutionNode = FALSE | ||
EndGlobalSection | ||
GlobalSection(ExtensibilityGlobals) = postSolution | ||
SolutionGuid = {4DB61618-5A93-468B-8A0B-97E62BE0DF3B} | ||
EndGlobalSection | ||
EndGlobal |