1
0
mirror of synced 2024-11-14 11:07:39 +01:00

Add GFPAK repacking

This commit is contained in:
KillzXGaming 2019-12-10 18:39:55 -05:00
parent a09db22b48
commit 5c4200884d

View File

@ -95,9 +95,9 @@ namespace FirstPlugin
public List<FileEntry> files = new List<FileEntry>();
public IEnumerable<ArchiveFileInfo> Files => files;
public void ClearFiles() { files.Clear(); }
public void ClearFiles() { files.Clear(); folders.Clear(); }
public bool CanAddFiles { get; set; } = false;
public bool CanAddFiles { get; set; } = true;
public bool CanRenameFiles { get; set; } = false;
public bool CanReplaceFiles { get; set; } = true;
public bool CanDeleteFiles { get; set; } = true;
@ -208,49 +208,16 @@ namespace FirstPlugin
for (int i = 0; i < FileCount; i++)
{
FileEntry fileEntry = new FileEntry(this);
fileEntry.Read(reader);
fileEntry.FileName = GetString(hashes[i], fileEntry.FileData);
fileEntry.FilePathHash = hashes[i];
for (int f = 0; f < FolderFiles.Count; f++)
if (FolderFiles[f].Index == f)
if (FolderFiles[f].Index == i)
fileEntry.FolderHash = FolderFiles[f];
string baseName = Path.GetFileName(fileEntry.FileName.Replace("\r", ""));
var dir = fileEntry.FolderHash.Parent;
switch (Utils.GetExtension(fileEntry.FileName))
{
case ".gfbanm":
// fileEntry.OpenFileFormatOnLoad = true;
fileEntry.FileName = $"Animations/{baseName}";
break;
case ".gfbanmcfg":
fileEntry.FileName = $"AnimationConfigs/{baseName}";
break;
case ".gfbmdl":
fileEntry.FileName = $"Models/{baseName}";
break;
case ".gfbpokecfg":
fileEntry.FileName = $"PokeConfigs/{baseName}";
break;
case ".bntx":
// fileEntry.OpenFileFormatOnLoad = true;
fileEntry.FileName = $"Textures/{baseName}";
break;
case ".bnsh":
fileEntry.FileName = $"Shaders/{baseName}";
break;
case ".ptcl":
fileEntry.FileName = $"Effects/{baseName}";
break;
default:
fileEntry.FileName = $"OtherFiles/{baseName}";
break;
}
// Console.WriteLine($"{fileEntry.FileName} {fileEntry.FolderHash.hash.ToString("X")} {suffix64.ToString("X")}");
fileEntry.Read(reader);
fileEntry.FileName = GetString(hashes[i], fileEntry.FolderHash, fileEntry.FileData);
fileEntry.FilePathHash = hashes[i];
files.Add(fileEntry);
}
@ -297,7 +264,7 @@ namespace FirstPlugin
//Also check file name just in case
if (FileName.Contains("pm"))
{
string baseName = Path.GetFileNameWithoutExtension(FileName);
string baseName = FileName.Substring(0, 12);
string pokeStrFile = hashStr.Replace("pm0000_00", baseName);
ulong hash = FNV64A1.Calculate(pokeStrFile);
@ -315,20 +282,60 @@ namespace FirstPlugin
}
}
private string GetString(ulong Hash, byte[] Data)
private string GetString(ulong fullHash, HashIndex fileHashIndex, byte[] Data)
{
var folderHash = fileHashIndex.Parent.hash;
var fileHash = fileHashIndex.hash;
bool hasFolderHash = false;
string folder = "";
if (HashList.ContainsKey(folderHash)) {
hasFolderHash = true;
folder = $"{HashList[folderHash]}/";
}
if (!hasFolderHash)
folder = $"{folderHash.ToString("X")}/";
string ext = FindMatch(Data);
if (ext == ".bntx" || ext == ".bfres" || ext == ".bnsh" || ext == ".bfsha")
return GetBinaryHeaderName(Data) + ext;
{
string fileName = GetBinaryHeaderName(Data);
//Check for matches for shaders
if (ext == ".bnsh")
{
if (FNV64A1.Calculate($"{fileName}.bnsh_fsh") == fileHash)
fileName = $"{fileName}.bnsh_fsh";
else if (FNV64A1.Calculate($"{fileName}.bnsh_vsh") == fileHash)
fileName = $"{fileName}.bnsh_vsh";
}
else
fileName = $"{fileName}{ext}";
if (hasFolderHash)
return $"{folder}{fileName}";
else
return $"{folder}{fileName}[FullHash={fullHash.ToString("X")}]{ext}";
}
else
{
if (HashList.ContainsKey(Hash))
return HashList[Hash];
if (HashList.ContainsKey(fileHash))
{
if (hasFolderHash)
return $"{folder}{HashList[fileHash]}";
else
return $"{Hash.ToString("X")}{ext}";
return $"{folder}{HashList[fileHash]}[FullHash={fullHash.ToString("X")}]{ext}";
}
else
return $"{folder}{fileHash.ToString("X")}[FullHash={fullHash.ToString("X")}]{ext}";
}
}
public void Write(FileWriter writer)
{
writer.WriteSignature("GFLXPACK");
@ -383,7 +390,7 @@ namespace FirstPlugin
{
public ulong hash;
public uint FileCount => (uint)hashes.Count;
public uint unknown;
public uint Padding = 0xCC;
public List<HashIndex> hashes = new List<HashIndex>();
@ -391,7 +398,7 @@ namespace FirstPlugin
{
hash = reader.ReadUInt64();
uint fileCount = reader.ReadUInt32();
unknown = reader.ReadUInt32();
Padding = reader.ReadUInt32();
for (int f = 0; f < fileCount; f++)
{
@ -404,7 +411,7 @@ namespace FirstPlugin
{
writer.Write(hash);
writer.Write(FileCount);
writer.Write(unknown);
writer.Write(Padding);
foreach (var hash in hashes)
hash.Write(writer);
@ -415,7 +422,7 @@ namespace FirstPlugin
{
public ulong hash;
public int Index;
public uint unknown;
public uint Padding = 0xCC;
public Folder Parent { get; set; }
@ -424,13 +431,13 @@ namespace FirstPlugin
Parent = parent;
hash = reader.ReadUInt64();
Index = reader.ReadInt32();
unknown = reader.ReadUInt32(); //Always 0xCC?
Padding = reader.ReadUInt32(); //Always 0xCC?
}
public void Write(FileWriter writer)
{
writer.Write(hash);
writer.Write(Index);
writer.Write(unknown);
writer.Write(Padding);
}
}
public class FileEntry : ArchiveFileInfo
@ -439,12 +446,12 @@ namespace FirstPlugin
public UInt64 FilePathHash;
public uint unkown;
public uint CompressionType;
public ushort Level = 9;
public CompressionType Type = CompressionType.Lz4;
private long DataOffset;
public uint CompressedFileSize;
public uint padding;
public uint Padding = 0xCC;
private IArchiveFile ArchiveFile;
@ -476,11 +483,11 @@ namespace FirstPlugin
public void Read(FileReader reader)
{
unkown = reader.ReadUInt16(); //Usually 9?
CompressionType = reader.ReadUInt16();
Level = reader.ReadUInt16(); //Usually 9?
Type = reader.ReadEnum<CompressionType>(true);
uint DecompressedFileSize = reader.ReadUInt32();
CompressedFileSize = reader.ReadUInt32();
padding = reader.ReadUInt32();
Padding = reader.ReadUInt32();
ulong FileOffset = reader.ReadUInt64();
using (reader.TemporarySeek((long)FileOffset, SeekOrigin.Begin))
@ -495,13 +502,13 @@ namespace FirstPlugin
{
this.SaveFileFormat();
CompressedData = Compress(FileData, CompressionType);
CompressedData = Compress(FileData, Type);
writer.Write((ushort)unkown);
writer.Write((ushort)CompressionType);
writer.Write(Level);
writer.Write(Type, true);
writer.Write(FileData.Length);
writer.Write(CompressedData.Length);
writer.Write(padding);
writer.Write(Padding);
DataOffset = writer.Position;
writer.Write(0L);
}
@ -511,15 +518,24 @@ namespace FirstPlugin
writer.WriteUint64Offset(DataOffset);
writer.Write(CompressedData);
}
public static byte[] Compress(byte[] data, uint Type)
{
if (Type == 2)
public static byte[] Compress(byte[] data, CompressionType Type)
{
if (Type == CompressionType.Lz4)
return STLibraryCompression.Type_LZ4.Compress(data);
}
else if (Type == CompressionType.None)
return data;
else if (Type == CompressionType.Zlib)
return STLibraryCompression.ZLIB.Compress(data);
else
throw new Exception("Unkown compression type?");
}
public enum CompressionType : ushort
{
None = 0,
Zlib = 1,
Lz4 = 2,
}
}
public static void ReplaceNode(TreeNode node, TreeNode replaceNode, TreeNode NewNode)
@ -534,7 +550,89 @@ namespace FirstPlugin
public bool AddFile(ArchiveFileInfo archiveFileInfo)
{
return false;
//First we need to determine the paths
string fullPath = archiveFileInfo.FileName.Replace("\\", "/");
string filePath = Path.GetFileName(fullPath);
string filePathNoExt = Path.GetFileNameWithoutExtension(fullPath);
string directoryPath = Path.GetDirectoryName(fullPath).Replace("\\", "/");
ulong fullPathHash = 0;
ulong directoryHash = 0;
ulong fileHash = 0;
//Calculate hashes for each one
//Check for full path hashes
if (fullPath.Contains("[FullHash="))
{
string HashString = fullPath.Split('=').LastOrDefault().Replace("]", string.Empty);
HashString = Path.GetFileNameWithoutExtension(HashString);
filePath = filePath.Split('[').FirstOrDefault();
TryParseHex(HashString, out fullPathHash);
}
ulong hash = 0;
bool isDirectoryHash = TryParseHex(directoryPath, out hash);
bool isFileHash = TryParseHex(filePath, out hash);
if (isFileHash)
TryParseHex(filePath, out fileHash);
else
fileHash = FNV64A1.Calculate(filePath);
if (isDirectoryHash)
TryParseHex(directoryPath, out directoryHash);
else
directoryHash = FNV64A1.Calculate($"{directoryPath}/");
if (!isFileHash && !isDirectoryHash)
fullPathHash = FNV64A1.Calculate(fullPath);
var folder = folders.FirstOrDefault(x => x.hash == directoryHash);
Console.WriteLine($"{fullPath} FilePathHash {fullPathHash}");
Console.WriteLine($"{directoryPath} FolderHash {directoryHash} directoryHash {directoryHash}");
Console.WriteLine($"{filePath} fileHash {fileHash} isFileHash {isFileHash}");
if (folder != null)
{
folder.hashes.Add(new HashIndex()
{
hash = fileHash,
Parent = folder,
Index = files.Count,
});
}
else
{
folder = new Folder();
folder.hash = directoryHash;
folder.hashes.Add(new HashIndex()
{
hash = fileHash,
Parent = folder,
Index = files.Count,
});
folders.Add(folder);
}
files.Add(new FileEntry(this)
{
FilePathHash = fullPathHash,
FolderHash = folder.hashes.LastOrDefault(),
FileData = archiveFileInfo.FileData,
FileDataStream = archiveFileInfo.FileDataStream,
FileName = archiveFileInfo.FileName,
});
return true;
}
private static bool TryParseHex(string str, out ulong value)
{
return ulong.TryParse(str, System.Globalization.NumberStyles.HexNumber, null, out value);
}
public bool DeleteFile(ArchiveFileInfo archiveFileInfo)