mirror of
https://github.com/kwsch/pk3DS.git
synced 2026-09-30 21:06:35 -05:00
Merge pull request #1 from kwsch/master
Update from upstream repo kwsch/pk3DS
This commit is contained in:
@@ -1,12 +1,240 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace CTR
|
||||
namespace pk3DS.Core.CTR
|
||||
{
|
||||
/// <summary>
|
||||
/// Archive LaYouT container
|
||||
/// </summary>
|
||||
/// <remarks> File length is padded to nearest 0x80 </remarks>
|
||||
public class ALYT
|
||||
{
|
||||
private const string Identifier = nameof(ALYT);
|
||||
public string Magic; // 0x00
|
||||
public short unk4; // 0x04
|
||||
public short unk6; // 0x06
|
||||
public int LTBLOffset; // 0x08
|
||||
public int LTBLSize; // 0x0C
|
||||
public int LMTLOffset; // 0x10
|
||||
public int LMTLSize; // 0x14
|
||||
public int LFNLOffset; // 0x18
|
||||
public int LFNLSize; // 0x1C
|
||||
|
||||
public int DataOffset; // 0x20
|
||||
public int DataSize; // 0x24
|
||||
|
||||
public LTBL LTBL;
|
||||
public LMTL LMTL;
|
||||
public LFNL LFNL;
|
||||
public Contents Content;
|
||||
public byte[] Data;
|
||||
|
||||
public string FileName { get; }
|
||||
public string FilePath { get; }
|
||||
public string Extension { get; }
|
||||
public bool SigMatches => Magic == Identifier;
|
||||
|
||||
public ALYT(string path)
|
||||
{
|
||||
FileName = Path.GetFileNameWithoutExtension(path);
|
||||
FilePath = Path.GetDirectoryName(path);
|
||||
Extension = Path.GetExtension(path);
|
||||
|
||||
using (var br = new BinaryReader(File.OpenRead(path)))
|
||||
ReadALYT(br);
|
||||
}
|
||||
|
||||
public ALYT(byte[] data)
|
||||
{
|
||||
using (var ms = new MemoryStream(data))
|
||||
using (var br = new BinaryReader(ms))
|
||||
ReadALYT(br);
|
||||
}
|
||||
|
||||
public ALYT(Stream ms)
|
||||
{
|
||||
using (var br = new BinaryReader(ms))
|
||||
ReadALYT(br);
|
||||
}
|
||||
|
||||
private void ReadALYT(BinaryReader br)
|
||||
{
|
||||
ReadHeader(br);
|
||||
LTBL = new LTBL(br, (LTBLSize - 8) / 4);
|
||||
LMTL = new LMTL(br, (LMTLSize - 8) / 4);
|
||||
LFNL = new LFNL(br, (LFNLSize - 8) / 4);
|
||||
Content = new Contents(br, this);
|
||||
}
|
||||
|
||||
private void ReadHeader(BinaryReader br)
|
||||
{
|
||||
Magic = new string(br.ReadChars(4));
|
||||
if (!SigMatches)
|
||||
return;
|
||||
unk4 = br.ReadInt16();
|
||||
unk6 = br.ReadInt16();
|
||||
LTBLOffset = br.ReadInt32();
|
||||
LTBLSize = br.ReadInt32();
|
||||
LMTLOffset = br.ReadInt32();
|
||||
LMTLSize = br.ReadInt32();
|
||||
LFNLOffset = br.ReadInt32();
|
||||
LFNLSize = br.ReadInt32();
|
||||
DataOffset = br.ReadInt32();
|
||||
DataSize = br.ReadInt32();
|
||||
}
|
||||
|
||||
public class Contents
|
||||
{
|
||||
public readonly string[] Labels;
|
||||
public readonly string[] Symbols;
|
||||
|
||||
public Contents(BinaryReader br, ALYT alyt)
|
||||
{
|
||||
br.BaseStream.Position = alyt.DataOffset;
|
||||
Labels = new string[br.ReadInt32()];
|
||||
for (int i = 0; i < Labels.Length; i++)
|
||||
Labels[i] = ReadString(br, 0x40);
|
||||
|
||||
Symbols = new string[br.ReadInt32()];
|
||||
for (int i = 0; i < Symbols.Length; i++)
|
||||
Symbols[i] = ReadString(br, 0x20);
|
||||
|
||||
// skip to end of section
|
||||
// this is bad
|
||||
while (br.PeekChar() == 0)
|
||||
br.ReadByte();
|
||||
|
||||
int len = (int)br.BaseStream.Position - alyt.DataOffset;
|
||||
len = alyt.DataSize - len;
|
||||
alyt.Data = br.ReadBytes(len);
|
||||
}
|
||||
|
||||
public static string ReadString(BinaryReader br, int skip)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
var ofs = br.BaseStream.Position;
|
||||
while (true)
|
||||
{
|
||||
var c = (char)br.ReadByte();
|
||||
if (c == 0)
|
||||
{
|
||||
br.BaseStream.Position = ofs + skip;
|
||||
return sb.ToString();
|
||||
}
|
||||
sb.Append(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rips out the data portion of the ALYT, assuming the ALYT is partially valid.
|
||||
/// </summary>
|
||||
public static byte[] GetData(string path)
|
||||
{
|
||||
using (var br = new BinaryReader(File.OpenRead(path)))
|
||||
return GetData(br);
|
||||
}
|
||||
/// <summary>
|
||||
/// Rips out the data portion of the ALYT, assuming the ALYT is partially valid.
|
||||
/// </summary>
|
||||
public static byte[] GetData(byte[] data)
|
||||
{
|
||||
using (var ms = new MemoryStream(data))
|
||||
using (var br = new BinaryReader(ms))
|
||||
return GetData(br);
|
||||
}
|
||||
/// <summary>
|
||||
/// Rips out the data portion of the ALYT, assuming the ALYT is partially valid.
|
||||
/// </summary>
|
||||
public static byte[] GetData(Stream ms)
|
||||
{
|
||||
using (var br = new BinaryReader(ms))
|
||||
return GetData(br);
|
||||
}
|
||||
private static byte[] GetData(BinaryReader br)
|
||||
{
|
||||
if (br.BaseStream.Length <= 0x80)
|
||||
return null;
|
||||
if (Identifier != new string(br.ReadChars(4)))
|
||||
return null; // not ALYT
|
||||
|
||||
br.BaseStream.Position = 0x20; // DataOffset
|
||||
int start = br.ReadInt32();
|
||||
int length = br.ReadInt32();
|
||||
|
||||
br.BaseStream.Position = start;
|
||||
int count40 = br.ReadInt32();
|
||||
br.BaseStream.Position += count40 * 0x40;
|
||||
|
||||
int count20 = br.ReadInt32();
|
||||
br.BaseStream.Position += count20 * 0x20;
|
||||
|
||||
// skip to end of section
|
||||
// this is bad
|
||||
while (br.PeekChar() == 0)
|
||||
br.ReadByte();
|
||||
|
||||
int len = (int)br.BaseStream.Position - start;
|
||||
len = length - len;
|
||||
return br.ReadBytes(len);
|
||||
}
|
||||
}
|
||||
|
||||
public class LTBL
|
||||
{
|
||||
private const string Identifier = nameof(LTBL);
|
||||
public string Magic; // 0x00
|
||||
public short unk4; // 0x04
|
||||
public short unk6; // 0x06
|
||||
public List<int> Values;
|
||||
|
||||
public LTBL(BinaryReader br, int count)
|
||||
{
|
||||
Magic = new string(br.ReadChars(Identifier.Length));
|
||||
unk4 = br.ReadInt16();
|
||||
unk6 = br.ReadInt16();
|
||||
Values = new List<int>(count);
|
||||
for (int i = 0; i < count; i++)
|
||||
Values.Add((short)br.ReadInt32());
|
||||
}
|
||||
}
|
||||
|
||||
public class LMTL
|
||||
{
|
||||
private const string Identifier = nameof(LMTL);
|
||||
public string Magic; // 0x00
|
||||
public short unk4; // 0x04
|
||||
public short unk6; // 0x06
|
||||
public List<int> Values;
|
||||
|
||||
public LMTL(BinaryReader br, int count)
|
||||
{
|
||||
Magic = new string(br.ReadChars(Identifier.Length));
|
||||
unk4 = br.ReadInt16();
|
||||
unk6 = br.ReadInt16();
|
||||
Values = new List<int>(count);
|
||||
for (int i = 0; i < count; i++)
|
||||
Values.Add((short)br.ReadInt32());
|
||||
}
|
||||
}
|
||||
|
||||
public class LFNL
|
||||
{
|
||||
private const string Identifier = nameof(LFNL);
|
||||
public string Magic; // 0x00
|
||||
public short unk4; // 0x04
|
||||
public short unk6; // 0x06
|
||||
public List<int> Values;
|
||||
|
||||
public LFNL(BinaryReader br, int count)
|
||||
{
|
||||
Magic = new string(br.ReadChars(Identifier.Length));
|
||||
unk4 = br.ReadInt16();
|
||||
unk6 = br.ReadInt16();
|
||||
Values = new List<int>(count);
|
||||
for (int i = 0; i < count; i++)
|
||||
Values.Add((short)br.ReadInt32());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
125
pk3DS.Core/CTR/SARC.cs
Normal file
125
pk3DS.Core/CTR/SARC.cs
Normal file
@@ -0,0 +1,125 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace pk3DS.Core.CTR
|
||||
{
|
||||
public class SARC
|
||||
{
|
||||
private const string Identifier = nameof(SARC);
|
||||
|
||||
public string Magic;
|
||||
public ushort HeaderSize;
|
||||
public ushort Endianness;
|
||||
public uint FileSize;
|
||||
public uint DataOffset;
|
||||
public uint Unknown;
|
||||
|
||||
public SFAT SFAT;
|
||||
public SFNT SFNT;
|
||||
|
||||
// Assigned Properties
|
||||
public string FileName;
|
||||
public string FilePath;
|
||||
public string Extension;
|
||||
public readonly bool Valid;
|
||||
|
||||
public bool SigMatches => Magic == Identifier;
|
||||
|
||||
public SARC()
|
||||
{
|
||||
SFAT = new SFAT();
|
||||
SFNT = new SFNT();
|
||||
}
|
||||
public SARC(string path)
|
||||
{
|
||||
FileName = Path.GetFileNameWithoutExtension(path);
|
||||
FilePath = Path.GetDirectoryName(path);
|
||||
Extension = Path.GetExtension(path);
|
||||
|
||||
using (var br = new BinaryReader(File.OpenRead(path)))
|
||||
{
|
||||
ReadHeader(br);
|
||||
SFAT = new SFAT(br);
|
||||
SFNT = new SFNT(br);
|
||||
}
|
||||
Valid = true;
|
||||
}
|
||||
private void ReadHeader(BinaryReader br)
|
||||
{
|
||||
Magic = new string(br.ReadChars(4));
|
||||
if (!SigMatches)
|
||||
return;
|
||||
|
||||
HeaderSize = br.ReadUInt16();
|
||||
Endianness = br.ReadUInt16();
|
||||
FileSize = br.ReadUInt32();
|
||||
DataOffset = br.ReadUInt32();
|
||||
Unknown = br.ReadUInt32();
|
||||
}
|
||||
}
|
||||
public class SFAT
|
||||
{
|
||||
public const string Identifier = nameof(SFAT);
|
||||
public bool SigMatches => Magic == Identifier;
|
||||
|
||||
public string Magic;
|
||||
public ushort HeaderSize;
|
||||
public ushort EntryCount;
|
||||
public uint HashMult;
|
||||
public List<SFATEntry> Entries;
|
||||
|
||||
public SFAT() { }
|
||||
public SFAT(BinaryReader br)
|
||||
{
|
||||
Magic = new string(br.ReadChars(4));
|
||||
if (!SigMatches)
|
||||
throw new FormatException(nameof(SFAT));
|
||||
|
||||
HeaderSize = br.ReadUInt16();
|
||||
EntryCount = br.ReadUInt16();
|
||||
HashMult = br.ReadUInt32();
|
||||
Entries = new List<SFATEntry>();
|
||||
|
||||
for (int i = 0; i < EntryCount; i++)
|
||||
Entries.Add(new SFATEntry(br));
|
||||
}
|
||||
}
|
||||
public class SFNT
|
||||
{
|
||||
public const string Identifier = nameof(SFNT);
|
||||
public bool SigMatches => Magic == Identifier;
|
||||
|
||||
public string Magic;
|
||||
public ushort HeaderSize;
|
||||
public ushort Unknown;
|
||||
public uint StringOffset;
|
||||
|
||||
public SFNT() { }
|
||||
public SFNT(BinaryReader br)
|
||||
{
|
||||
Magic = new string(br.ReadChars(4));
|
||||
if (!SigMatches)
|
||||
throw new FormatException(nameof(SFNT));
|
||||
|
||||
HeaderSize = br.ReadUInt16();
|
||||
Unknown = br.ReadUInt16();
|
||||
StringOffset = (uint)br.BaseStream.Position;
|
||||
}
|
||||
}
|
||||
public class SFATEntry
|
||||
{
|
||||
public uint FileNameHash;
|
||||
public uint FileNameOffset;
|
||||
public uint FileDataStart;
|
||||
public uint FileDataEnd;
|
||||
|
||||
public SFATEntry(BinaryReader br)
|
||||
{
|
||||
FileNameHash = br.ReadUInt32();
|
||||
FileNameOffset = br.ReadUInt32();
|
||||
FileDataStart = br.ReadUInt32();
|
||||
FileDataEnd = br.ReadUInt32();
|
||||
}
|
||||
}
|
||||
}
|
||||
230
pk3DS/ARCUtil.cs
230
pk3DS/ARCUtil.cs
@@ -1,67 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using pk3DS.Core.CTR;
|
||||
|
||||
namespace pk3DS.ARCUtil
|
||||
{
|
||||
public static class ARC
|
||||
{
|
||||
// Multi Type Archive Handling
|
||||
internal static bool onefile = true;
|
||||
internal static SARC analyzeSARC(string path)
|
||||
private static SARC analyzeSARC(string path)
|
||||
{
|
||||
SARC sarc = new SARC
|
||||
{
|
||||
FileName = Path.GetFileNameWithoutExtension(path),
|
||||
FilePath = Path.GetDirectoryName(path),
|
||||
Extension = Path.GetExtension(path)
|
||||
};
|
||||
BinaryReader br = new BinaryReader(File.OpenRead(path));
|
||||
sarc.valid = true;
|
||||
sarc.Signature = new string(br.ReadChars(4));
|
||||
if (sarc.Signature != "SARC")
|
||||
{
|
||||
sarc.valid = false;
|
||||
return sarc;
|
||||
}
|
||||
sarc.HeaderSize = br.ReadUInt16();
|
||||
sarc.Endianness = br.ReadUInt16();
|
||||
sarc.FileSize = br.ReadUInt32();
|
||||
sarc.DataOffset = br.ReadUInt32();
|
||||
sarc.Unknown = br.ReadUInt32();
|
||||
sarc.SFat = new SFAT { Signature = new string(br.ReadChars(4)) };
|
||||
if (sarc.SFat.Signature != "SFAT")
|
||||
{
|
||||
sarc.valid = false;
|
||||
return sarc;
|
||||
}
|
||||
sarc.SFat.HeaderSize = br.ReadUInt16();
|
||||
sarc.SFat.EntryCount = br.ReadUInt16();
|
||||
sarc.SFat.HashMult = br.ReadUInt32();
|
||||
sarc.SFat.Entries = new List<SFATEntry>();
|
||||
for (int i = 0; i < sarc.SFat.EntryCount; i++)
|
||||
{
|
||||
SFATEntry s = new SFATEntry
|
||||
{
|
||||
FileNameHash = br.ReadUInt32(),
|
||||
FileNameOffset = br.ReadUInt32(),
|
||||
FileDataStart = br.ReadUInt32(),
|
||||
FileDataEnd = br.ReadUInt32()
|
||||
};
|
||||
sarc.SFat.Entries.Add(s);
|
||||
}
|
||||
sarc.SFnt = new SFNT { Signature = new string(br.ReadChars(4)) };
|
||||
if (sarc.SFnt.Signature != "SFNT")
|
||||
{
|
||||
sarc.valid = false;
|
||||
return sarc;
|
||||
}
|
||||
sarc.SFnt.HeaderSize = br.ReadUInt16();
|
||||
sarc.SFnt.Unknown = br.ReadUInt16();
|
||||
sarc.SFnt.StringOffset = (uint)br.BaseStream.Position;
|
||||
return sarc;
|
||||
try { return new SARC(path); }
|
||||
catch { return new SARC(); }
|
||||
}
|
||||
internal static ShuffleARC AnalyzeShuffle(string path)
|
||||
{
|
||||
@@ -430,73 +382,86 @@ internal static string Interpret(string path)
|
||||
}
|
||||
else if (sharc.valid)
|
||||
{
|
||||
ret += "New Shuffle Archive with " + sharc.FileCount + " files." + Environment.NewLine;
|
||||
string dir = Path.GetDirectoryName(path) + Path.DirectorySeparatorChar + sharc.FileName + "_" + Path.DirectorySeparatorChar;
|
||||
if (!Directory.Exists(dir))
|
||||
{
|
||||
Console.WriteLine("Making dir: " + dir);
|
||||
Directory.CreateDirectory(dir);
|
||||
}
|
||||
|
||||
string diglen = "".PadLeft((int)(Math.Log10(sharc.FileCount) + 1), '0');
|
||||
for (int i = 0; i < sharc.FileCount; i++)
|
||||
{
|
||||
var fs = File.OpenRead(path);
|
||||
fs.Seek(sharc.Files[i].Offset, SeekOrigin.Begin);
|
||||
byte[] fileBuffer = new byte[sharc.Files[i].Length];
|
||||
fs.Read(fileBuffer, 0, fileBuffer.Length);
|
||||
fs.Close();
|
||||
uint check = 0;
|
||||
for (int j = 0; j < fileBuffer.Length; j += 4)
|
||||
check += BitConverter.ToUInt32(fileBuffer, j);
|
||||
Console.WriteLine(i.ToString(diglen) + ": " + check.ToString("X8"));
|
||||
File.WriteAllBytes(dir + i.ToString(diglen) + ".zip", fileBuffer);
|
||||
ret += "Extracted " + i.ToString(diglen) + " (Offset: " + sharc.Files[i].Offset.ToString("X8") + ", Len: " + sharc.Files[i].Length.ToString("X8") + ")." + Environment.NewLine;
|
||||
}
|
||||
ret += Environment.NewLine;
|
||||
}
|
||||
else if (sarc.valid)
|
||||
{
|
||||
ret = "New SARC with " + sarc.SFat.EntryCount + " files." + Environment.NewLine;
|
||||
string dir = Path.GetDirectoryName(path) + Path.DirectorySeparatorChar + sarc.FileName + "_" + Path.DirectorySeparatorChar;
|
||||
if (!Directory.Exists(dir))
|
||||
{
|
||||
Console.WriteLine("Making dir: " + dir);
|
||||
Directory.CreateDirectory(dir);
|
||||
}
|
||||
|
||||
foreach (SFATEntry t in sarc.SFat.Entries)
|
||||
{
|
||||
var fs = File.OpenRead(path);
|
||||
uint FileLen = t.FileDataEnd - t.FileDataStart;
|
||||
fs.Seek(t.FileDataStart + sarc.DataOffset, SeekOrigin.Begin);
|
||||
byte[] fileBuffer = new byte[FileLen];
|
||||
fs.Read(fileBuffer, 0, (int)FileLen);
|
||||
fs.Seek(sarc.SFnt.StringOffset, SeekOrigin.Begin);
|
||||
fs.Seek((t.FileNameOffset & 0x00FFFFFF) * 4, SeekOrigin.Current);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (char c = (char)fs.ReadByte(); c != 0; c = (char)fs.ReadByte())
|
||||
{
|
||||
sb.Append(c);
|
||||
}
|
||||
string FileName = sb.ToString().Replace('/', Path.DirectorySeparatorChar);
|
||||
fs.Close();
|
||||
string FileDir = Path.GetDirectoryName(dir + FileName) + Path.DirectorySeparatorChar;
|
||||
if (!Directory.Exists(FileDir))
|
||||
{
|
||||
Console.WriteLine("Making dir: " + FileDir);
|
||||
Directory.CreateDirectory(FileDir);
|
||||
}
|
||||
File.WriteAllBytes(dir + FileName, fileBuffer);
|
||||
}
|
||||
UnpackShuffleARC(path, sharc, ret);
|
||||
}
|
||||
else if (sarc.Valid)
|
||||
UnpackSARC(path, sarc);
|
||||
else
|
||||
{
|
||||
ret = "Not a valid .DARC/.FARC/.SARC/.GAR/Shuffle Archive file";
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
private static bool UnpackShuffleARC(string path, ShuffleARC sharc, string ret)
|
||||
{
|
||||
Debug.WriteLine($"New Shuffle Archive with {sharc.FileCount} files.");
|
||||
string dir = Path.GetDirectoryName(path) + Path.DirectorySeparatorChar + sharc.FileName + "_" + Path.DirectorySeparatorChar;
|
||||
if (!Directory.Exists(dir))
|
||||
{
|
||||
Console.WriteLine("Making dir: " + dir);
|
||||
Directory.CreateDirectory(dir);
|
||||
}
|
||||
|
||||
string diglen = "".PadLeft((int)(Math.Log10(sharc.FileCount) + 1), '0');
|
||||
for (int i = 0; i < sharc.FileCount; i++)
|
||||
{
|
||||
var fs = File.OpenRead(path);
|
||||
fs.Seek(sharc.Files[i].Offset, SeekOrigin.Begin);
|
||||
byte[] fileBuffer = new byte[sharc.Files[i].Length];
|
||||
fs.Read(fileBuffer, 0, fileBuffer.Length);
|
||||
fs.Close();
|
||||
uint check = 0;
|
||||
for (int j = 0; j < fileBuffer.Length; j += 4)
|
||||
check += BitConverter.ToUInt32(fileBuffer, j);
|
||||
Console.WriteLine(i.ToString(diglen) + ": " + check.ToString("X8"));
|
||||
File.WriteAllBytes(dir + i.ToString(diglen) + ".zip", fileBuffer);
|
||||
Debug.WriteLine($"Extracted {i.ToString(diglen)} (Offset: {sharc.Files[i].Offset:X8}, Len: {sharc.Files[i].Length:X8}).");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool UnpackSARC(string path, SARC sarc)
|
||||
{
|
||||
Debug.WriteLine($"New SARC with {sarc.SFAT.EntryCount} files.");
|
||||
string dir = Path.GetDirectoryName(path) + Path.DirectorySeparatorChar + sarc.FileName + "_" + Path.DirectorySeparatorChar;
|
||||
if (!Directory.Exists(dir))
|
||||
{
|
||||
Debug.WriteLine($"Making dir: {dir}");
|
||||
Directory.CreateDirectory(dir);
|
||||
}
|
||||
|
||||
var fs = File.OpenRead(path);
|
||||
foreach (SFATEntry t in sarc.SFAT.Entries)
|
||||
{
|
||||
// Read File Data
|
||||
uint FileLen = t.FileDataEnd - t.FileDataStart;
|
||||
fs.Seek(t.FileDataStart + sarc.DataOffset, SeekOrigin.Begin);
|
||||
byte[] fileBuffer = new byte[FileLen];
|
||||
fs.Read(fileBuffer, 0, (int)FileLen);
|
||||
|
||||
// Read File Name
|
||||
fs.Seek(sarc.SFNT.StringOffset, SeekOrigin.Begin);
|
||||
fs.Seek((t.FileNameOffset & 0x00FFFFFF) * 4, SeekOrigin.Current);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (char c = (char)fs.ReadByte(); c != 0; c = (char)fs.ReadByte())
|
||||
sb.Append(c);
|
||||
|
||||
// Write File
|
||||
string FileName = sb.ToString().Replace('/', Path.DirectorySeparatorChar);
|
||||
string FileDir = Path.GetDirectoryName(dir + FileName) + Path.DirectorySeparatorChar;
|
||||
if (!Directory.Exists(FileDir))
|
||||
{
|
||||
Console.WriteLine($"Making dir: {FileDir}");
|
||||
Directory.CreateDirectory(FileDir);
|
||||
}
|
||||
File.WriteAllBytes(dir + FileName, fileBuffer);
|
||||
}
|
||||
fs.Close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Unpacking
|
||||
internal static string unpackDARC(string path, string outFolder = null, bool delete = true)
|
||||
{
|
||||
@@ -668,45 +633,6 @@ public struct FARCFile
|
||||
public string Name;
|
||||
}
|
||||
|
||||
public class SARC
|
||||
{
|
||||
public string Signature;
|
||||
public ushort HeaderSize = 0x14;
|
||||
public ushort Endianness;
|
||||
public uint FileSize;
|
||||
public uint DataOffset;
|
||||
public uint Unknown;
|
||||
public SFAT SFat;
|
||||
public SFNT SFnt;
|
||||
|
||||
public string FileName;
|
||||
public string FilePath;
|
||||
public string Extension;
|
||||
public bool valid;
|
||||
}
|
||||
public class SFAT
|
||||
{
|
||||
public string Signature;
|
||||
public ushort HeaderSize;
|
||||
public ushort EntryCount;
|
||||
public uint HashMult;
|
||||
public List<SFATEntry> Entries;
|
||||
}
|
||||
public class SFATEntry
|
||||
{
|
||||
public uint FileNameHash;
|
||||
public uint FileNameOffset;
|
||||
public uint FileDataStart;
|
||||
public uint FileDataEnd;
|
||||
}
|
||||
public class SFNT
|
||||
{
|
||||
public string Signature;
|
||||
public ushort HeaderSize;
|
||||
public ushort Unknown;
|
||||
public uint StringOffset;
|
||||
}
|
||||
|
||||
public class ShuffleARC
|
||||
{
|
||||
public uint magic; //0xB
|
||||
|
||||
Reference in New Issue
Block a user