Template
267 lines
8.4 KiB
C#
267 lines
8.4 KiB
C#
using System;
|
|||
|
|
using System.Collections.Generic;
|
||
|
|
using System.IO;
|
||
|
|
using System.Linq;
|
||
|
|
using System.Runtime.InteropServices;
|
||
|
|
using System.Text;
|
||
|
|
|
||
|
|
namespace FireTools {
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
namespace Native
|
||
|
|
{
|
||
|
|
public struct Header {
|
||
|
|
public struct PageDesc {
|
||
|
|
public uint offset;
|
||
|
|
public uint size;
|
||
|
|
public uint index;
|
||
|
|
};
|
||
|
|
public struct SomeRecordTableDesc {
|
||
|
|
public uint unk3;
|
||
|
|
public uint someRecordsOffset;
|
||
|
|
public uint someRecordsCount;
|
||
|
|
};
|
||
|
|
|
||
|
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||
|
|
public struct BaseInfo {
|
||
|
|
public ushort magic;
|
||
|
|
public ushort someType;
|
||
|
|
public uint totalHeaderSize;
|
||
|
|
public uint loginTableFilePageId;
|
||
|
|
public uint loginTableFileOffset;
|
||
|
|
public uint pagesCount;
|
||
|
|
public uint pageTableOffset;
|
||
|
|
public uint someConstantValue; // always == 8
|
||
|
|
public uint someRecordTableDescOffset; // always == 8
|
||
|
|
public uint someAttachedDataSize; //bottom of pak file (after last page)
|
||
|
|
|
||
|
|
public uint vramDescTableFilePageId;
|
||
|
|
public uint vramDescTableFileOffset;
|
||
|
|
}
|
||
|
|
|
||
|
|
public BaseInfo baseInfo;
|
||
|
|
|
||
|
|
public PageDesc[] pageTable;
|
||
|
|
|
||
|
|
public SomeRecordTableDesc someRecordTableDesc;
|
||
|
|
|
||
|
|
public byte[] someZeroData;
|
||
|
|
|
||
|
|
public struct SomeRecord {
|
||
|
|
public ushort w0;
|
||
|
|
public ushort w1;
|
||
|
|
public uint v1;
|
||
|
|
};
|
||
|
|
|
||
|
|
public SomeRecord[] someRecords;
|
||
|
|
}
|
||
|
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||
|
|
public struct FileHeader {
|
||
|
|
public uint fileNameOffset;
|
||
|
|
public uint alwaysZeroValue;
|
||
|
|
public uint fileClassNameOffset;
|
||
|
|
public uint u3;
|
||
|
|
public uint fileSize;
|
||
|
|
public uint dummy0; //0x12345
|
||
|
|
public uint dummy1; //0x12345
|
||
|
|
public uint dummy2; //0x12345
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
public class Page
|
||
|
|
{
|
||
|
|
public PakFileInput pakFile;
|
||
|
|
public uint id;
|
||
|
|
public class File
|
||
|
|
{
|
||
|
|
public PakFileInput Pak => page.pakFile;
|
||
|
|
public Page page;
|
||
|
|
public uint id;
|
||
|
|
public Native.FileHeader header;
|
||
|
|
public uint Size => header.fileSize;
|
||
|
|
public uint LocalOffset => page.fileTable[id].fileOffset;
|
||
|
|
public uint GlobalOffset => LocalOffset + page.Offset;
|
||
|
|
|
||
|
|
public uint LocalDataOffset => (uint)(page.fileTable[id].fileOffset + Marshal.SizeOf<Native.FileHeader>());
|
||
|
|
public uint GlobalDataOffset => LocalDataOffset + page.Offset;
|
||
|
|
|
||
|
|
public string name;
|
||
|
|
public string className;
|
||
|
|
}
|
||
|
|
public int FilesCount => baseInfo.filesTableHeader.filesCount;
|
||
|
|
|
||
|
|
public uint Offset => pakFile.header.pageTable[id].offset;
|
||
|
|
public uint Size => pakFile.header.pageTable[id].size;
|
||
|
|
|
||
|
|
public long TotalFilesSize {
|
||
|
|
get {
|
||
|
|
return files.Select(v => (long)v.header.fileSize).Sum();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
public Native.Header.PageDesc desc;
|
||
|
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||
|
|
public struct BaseInfo {
|
||
|
|
public struct FilesTableHeader {
|
||
|
|
public ushort unk0;
|
||
|
|
public ushort filesCount;
|
||
|
|
}
|
||
|
|
|
||
|
|
public uint magic0; //0xDEADBEEF
|
||
|
|
public uint magic1; //0xDEADBEEF
|
||
|
|
|
||
|
|
public uint unk0;
|
||
|
|
public uint fullPageSize;
|
||
|
|
|
||
|
|
public FilesTableHeader filesTableHeader;
|
||
|
|
}
|
||
|
|
|
||
|
|
public BaseInfo baseInfo;
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
public struct FileTableRecord {
|
||
|
|
public uint fileNameOffset;
|
||
|
|
public uint alwaysZeroValue;
|
||
|
|
public uint fileOffset;
|
||
|
|
public uint dummy;
|
||
|
|
}
|
||
|
|
|
||
|
|
public FileTableRecord[] fileTable;
|
||
|
|
public File[] files;
|
||
|
|
}
|
||
|
|
|
||
|
|
public class VRamDescFile {
|
||
|
|
public struct Header {
|
||
|
|
public uint u0;
|
||
|
|
public uint u1;
|
||
|
|
public uint maybeOffset;
|
||
|
|
public uint u3;
|
||
|
|
public uint maybeLength;
|
||
|
|
public ushort h0;
|
||
|
|
public ushort h1;
|
||
|
|
public ushort h2;
|
||
|
|
public ushort h3;
|
||
|
|
public uint maybeFormat;
|
||
|
|
|
||
|
|
public ushort h6;
|
||
|
|
public ushort h7;
|
||
|
|
public uint mipCount;
|
||
|
|
public uint width;
|
||
|
|
public uint height;
|
||
|
|
public uint u12;
|
||
|
|
public uint u13;
|
||
|
|
public uint u14;
|
||
|
|
public uint u15;
|
||
|
|
}
|
||
|
|
|
||
|
|
public Header header;
|
||
|
|
public string fileName;
|
||
|
|
public Page.File file;
|
||
|
|
|
||
|
|
public static VRamDescFile Read(Stream stream, Page.File file) {
|
||
|
|
var result = new VRamDescFile();
|
||
|
|
result.file = file;
|
||
|
|
stream.Seek(file.GlobalDataOffset, SeekOrigin.Begin);
|
||
|
|
stream.ReadValue(out result.header);
|
||
|
|
result.fileName = stream.ReadString();
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
public byte[] ReadRawData(Stream stm)
|
||
|
|
{
|
||
|
|
stm.Seek((long)stm.Length - file.Pak.RawDataSize + header.maybeOffset, SeekOrigin.Begin);
|
||
|
|
return stm.ReadBytes((int)header.maybeLength);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
public class PakFileInput {
|
||
|
|
public string sourceName;
|
||
|
|
public long realFullSize;
|
||
|
|
public Native.Header header;
|
||
|
|
public Page[] pages;
|
||
|
|
|
||
|
|
public uint RawDataSize => header.baseInfo.someAttachedDataSize;
|
||
|
|
public int TotalFilesCount {
|
||
|
|
get {
|
||
|
|
return pages.Select(v => v.files.Length).Sum();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public PakFileInput(Stream stm, string sourceName) {
|
||
|
|
this.sourceName = sourceName;
|
||
|
|
realFullSize = stm.Length;
|
||
|
|
stm.Seek(0, SeekOrigin.Begin);
|
||
|
|
|
||
|
|
ParseHeader(stm);
|
||
|
|
|
||
|
|
pages = new Page[header.baseInfo.pagesCount];
|
||
|
|
for (uint i = 0; i < pages.Length; ++i) {
|
||
|
|
pages[i] = ParsePage(stm, i);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private Page ParsePage(Stream stm, uint id) {
|
||
|
|
Page result = new Page();
|
||
|
|
result.id = id;
|
||
|
|
result.pakFile = this;
|
||
|
|
|
||
|
|
var pageDesc = header.pageTable[id];
|
||
|
|
result.desc = pageDesc;
|
||
|
|
|
||
|
|
stm.Seek(pageDesc.offset, SeekOrigin.Begin);
|
||
|
|
|
||
|
|
stm.ReadValue(out result.baseInfo);
|
||
|
|
|
||
|
|
result.fileTable = new Page.FileTableRecord[result.FilesCount];
|
||
|
|
for (uint i = 0; i < result.FilesCount; ++i) {
|
||
|
|
stm.ReadValue(out result.fileTable[i]);
|
||
|
|
}
|
||
|
|
|
||
|
|
result.files = new Page.File[result.FilesCount];
|
||
|
|
for (uint i = 0; i < result.FilesCount; ++i) {
|
||
|
|
result.files[i] = new Page.File();
|
||
|
|
result.files[i].id = i;
|
||
|
|
result.files[i].page = result;
|
||
|
|
stm.Seek(pageDesc.offset + result.fileTable[i].fileOffset, SeekOrigin.Begin);
|
||
|
|
stm.ReadValue(out result.files[i].header);
|
||
|
|
|
||
|
|
stm.Seek(pageDesc.offset + result.files[i].header.fileNameOffset, SeekOrigin.Begin);
|
||
|
|
result.files[i].name = stm.ReadString();
|
||
|
|
stm.Seek(pageDesc.offset + result.files[i].header.fileClassNameOffset, SeekOrigin.Begin);
|
||
|
|
result.files[i].className = stm.ReadString();
|
||
|
|
}
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
private void ParseHeader(Stream stm) {
|
||
|
|
stm.ReadValue(out header.baseInfo);
|
||
|
|
|
||
|
|
header.pageTable = new Native.Header.PageDesc[header.baseInfo.pagesCount];
|
||
|
|
for (uint i = 0; i < header.baseInfo.pagesCount; ++i) {
|
||
|
|
stm.ReadValue(out header.pageTable[i]);
|
||
|
|
}
|
||
|
|
|
||
|
|
stm.Seek(header.baseInfo.someRecordTableDescOffset, SeekOrigin.Begin);
|
||
|
|
stm.ReadValue(out header.someRecordTableDesc);
|
||
|
|
|
||
|
|
var someZeroDataSize = (int)(header.someRecordTableDesc.someRecordsOffset - stm.Position);
|
||
|
|
header.someZeroData = stm.ReadBytes(someZeroDataSize);
|
||
|
|
|
||
|
|
if (header.someRecordTableDesc.someRecordsCount != 0) {
|
||
|
|
header.someRecords = new Native.Header.SomeRecord[header.someRecordTableDesc.someRecordsCount];
|
||
|
|
for (uint i = 0; i < header.someRecords.Length; ++i) {
|
||
|
|
stm.ReadValue(out header.someRecords[i]);
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
header.someRecords = new Native.Header.SomeRecord[0];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|