2019-08-17 00:07:03 +02:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using System.Runtime.InteropServices;
|
2019-08-20 22:52:48 +02:00
|
|
|
|
using Toolbox.Library;
|
|
|
|
|
using Toolbox.Library.IO;
|
2019-08-17 00:07:03 +02:00
|
|
|
|
|
|
|
|
|
namespace DKCTF
|
|
|
|
|
{
|
2019-08-20 22:52:48 +02:00
|
|
|
|
public class PAK : TreeNodeFile, IArchiveFile, IFileFormat, ILeaveOpenOnLoad
|
|
|
|
|
{
|
|
|
|
|
public FileType FileType { get; set; } = FileType.Layout;
|
|
|
|
|
|
|
|
|
|
public bool CanSave { get; set; }
|
2019-08-20 23:22:01 +02:00
|
|
|
|
public string[] Description { get; set; } = new string[] { "DKCTF Archive" };
|
|
|
|
|
public string[] Extension { get; set; } = new string[] { "*.pak" };
|
2019-08-20 22:52:48 +02:00
|
|
|
|
public string FileName { get; set; }
|
|
|
|
|
public string FilePath { get; set; }
|
|
|
|
|
public IFileInfo IFileInfo { get; set; }
|
|
|
|
|
|
|
|
|
|
public bool CanAddFiles { get; set; }
|
|
|
|
|
public bool CanRenameFiles { get; set; }
|
|
|
|
|
public bool CanReplaceFiles { get; set; }
|
|
|
|
|
public bool CanDeleteFiles { get; set; }
|
|
|
|
|
|
|
|
|
|
public bool Identify(System.IO.Stream stream)
|
|
|
|
|
{
|
|
|
|
|
using (var reader = new Toolbox.Library.IO.FileReader(stream, true))
|
|
|
|
|
{
|
|
|
|
|
bool IsForm = reader.CheckSignature(4, "RFRM");
|
|
|
|
|
bool FormType = reader.CheckSignature(4, "PACK", 20);
|
|
|
|
|
|
|
|
|
|
return IsForm && FormType;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Type[] Types
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
List<Type> types = new List<Type>();
|
|
|
|
|
return types.ToArray();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public List<FileEntry> files = new List<FileEntry>();
|
|
|
|
|
public IEnumerable<ArchiveFileInfo> Files => files;
|
|
|
|
|
|
|
|
|
|
public void ClearFiles() { files.Clear(); }
|
|
|
|
|
|
|
|
|
|
private PakHeader Header;
|
|
|
|
|
private List<DirectoryAssetEntry> Directories = new List<DirectoryAssetEntry>();
|
|
|
|
|
private List<MetaOffsetEntry> MetaOffsets = new List<MetaOffsetEntry>();
|
|
|
|
|
private List<CNameTagEntry> FileNameEntries = new List<CNameTagEntry>();
|
|
|
|
|
|
|
|
|
|
public void Load(System.IO.Stream stream)
|
|
|
|
|
{
|
|
|
|
|
Directories.Clear();
|
|
|
|
|
MetaOffsets.Clear();
|
|
|
|
|
FileNameEntries.Clear();
|
|
|
|
|
|
|
|
|
|
using (var reader = new FileReader(stream, true))
|
|
|
|
|
{
|
|
|
|
|
reader.SetByteOrder(true);
|
|
|
|
|
Header = reader.ReadStruct<PakHeader>();
|
|
|
|
|
var ADIRChunk = reader.ReadStruct<CChunkDescriptor>();
|
|
|
|
|
ReadAssetDirectoryChunk(reader, ADIRChunk);
|
|
|
|
|
var METAChunk = reader.ReadStruct<CChunkDescriptor>();
|
|
|
|
|
ReadMetaChunk(reader, METAChunk);
|
|
|
|
|
var STRGChunk = reader.ReadStruct<CChunkDescriptor>();
|
|
|
|
|
ReadFileNameChunk(reader, STRGChunk);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < Directories.Count; i++)
|
|
|
|
|
{
|
|
|
|
|
files.Add(new FileEntry()
|
|
|
|
|
{
|
|
|
|
|
FileData = new byte[0],
|
|
|
|
|
FileDataStream = Directories[i].Data,
|
|
|
|
|
FileName = Directories[i].Type,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
/* var file = STFileLoader.OpenFileFormat(subStream, Directories[i].ToString());
|
|
|
|
|
if (file != null && file is TreeNodeFile)
|
|
|
|
|
{
|
|
|
|
|
Nodes.Add((TreeNodeFile)file);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}*/
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void ReadAssetDirectoryChunk(FileReader reader, CChunkDescriptor chunk)
|
|
|
|
|
{
|
|
|
|
|
if (chunk.ChunkType != "ADIR")
|
|
|
|
|
throw new Exception("Unexpected type! Expected ADIR, got " + chunk.ChunkType);
|
|
|
|
|
|
|
|
|
|
long pos = reader.Position;
|
|
|
|
|
|
|
|
|
|
reader.SeekBegin(pos + chunk.DataOffset);
|
|
|
|
|
uint numEntries = reader.ReadUInt32();
|
|
|
|
|
for (int i = 0; i < numEntries; i++)
|
|
|
|
|
{
|
|
|
|
|
DirectoryAssetEntry entry = new DirectoryAssetEntry();
|
|
|
|
|
entry.Read(reader);
|
|
|
|
|
Directories.Add(entry);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
reader.SeekBegin(pos + chunk.DataSize);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void ReadMetaChunk(FileReader reader, CChunkDescriptor chunk)
|
|
|
|
|
{
|
|
|
|
|
if (chunk.ChunkType != "META")
|
|
|
|
|
throw new Exception("Unexpected type! Expected META, got " + chunk.ChunkType);
|
|
|
|
|
long pos = reader.Position;
|
|
|
|
|
reader.SeekBegin(pos + chunk.DataOffset);
|
|
|
|
|
uint numEntries = reader.ReadUInt32();
|
|
|
|
|
for (int i = 0; i < numEntries; i++)
|
|
|
|
|
{
|
|
|
|
|
MetaOffsetEntry entry = reader.ReadStruct< MetaOffsetEntry>();
|
|
|
|
|
MetaOffsets.Add(entry);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
reader.SeekBegin(pos + chunk.DataSize);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void ReadFileNameChunk(FileReader reader, CChunkDescriptor chunk)
|
|
|
|
|
{
|
|
|
|
|
if (chunk.ChunkType != "STRG")
|
|
|
|
|
throw new Exception("Unexpected type! Expected STRG, got " + chunk.ChunkType);
|
|
|
|
|
|
|
|
|
|
long pos = reader.Position;
|
|
|
|
|
reader.SeekBegin(pos + chunk.DataOffset);
|
|
|
|
|
uint numEntries = reader.ReadUInt32();
|
|
|
|
|
for (int i = 0; i < numEntries; i++)
|
|
|
|
|
{
|
|
|
|
|
// CNameTagEntry entry = reader.ReadStruct<CNameTagEntry>();
|
|
|
|
|
// FileNameEntries.Add(entry);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
reader.SeekBegin(pos + chunk.DataSize);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Unload()
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Save(System.IO.Stream stream)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool AddFile(ArchiveFileInfo archiveFileInfo)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool DeleteFile(ArchiveFileInfo archiveFileInfo)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class FileEntry : ArchiveFileInfo
|
2019-08-17 00:07:03 +02:00
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-20 22:52:48 +02:00
|
|
|
|
public class DirectoryAssetEntry
|
|
|
|
|
{
|
|
|
|
|
public string Type;
|
|
|
|
|
public CObjectId FileID;
|
|
|
|
|
|
|
|
|
|
public long Offset;
|
|
|
|
|
public long Size;
|
|
|
|
|
|
|
|
|
|
public SubStream Data;
|
|
|
|
|
|
|
|
|
|
public void Read(FileReader reader)
|
|
|
|
|
{
|
|
|
|
|
Type = reader.ReadString(4, Encoding.ASCII);
|
|
|
|
|
FileID = reader.ReadStruct<CObjectId>();
|
|
|
|
|
Offset = reader.ReadInt64();
|
|
|
|
|
Size = reader.ReadInt64();
|
|
|
|
|
|
|
|
|
|
Data = new SubStream(reader.BaseStream, Offset,Size);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override string ToString()
|
|
|
|
|
{
|
|
|
|
|
return $"{FileID.Guid.Part4.ToString()}.{Type}";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
|
|
|
|
public class MetaOffsetEntry
|
|
|
|
|
{
|
|
|
|
|
public CObjectTag ObjectTag;
|
|
|
|
|
public uint FileOffset;
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-17 00:07:03 +02:00
|
|
|
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
|
|
|
|
public class PakHeader
|
|
|
|
|
{
|
|
|
|
|
CFormDescriptor PackForm;
|
2019-08-20 22:52:48 +02:00
|
|
|
|
CFormDescriptor TocForm;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
|
|
|
|
public class CNameTagEntry
|
|
|
|
|
{
|
|
|
|
|
public CObjectTag ObjectTag;
|
|
|
|
|
public string Name;
|
2019-08-17 00:07:03 +02:00
|
|
|
|
}
|
|
|
|
|
}
|