mirror of
https://github.com/crskycode/GARbro.git
synced 2026-07-08 01:30:18 +08:00
(fPK): implemented archives version 2.
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
//! \date Mon Sep 12 01:39:49 2016
|
//! \date Mon Sep 12 01:39:49 2016
|
||||||
//! \brief 'fPK' resource archive.
|
//! \brief 'fPK' resource archive.
|
||||||
//
|
//
|
||||||
// Copyright (C) 2016 by morkt
|
// Copyright (C) 2016-2017 by morkt
|
||||||
//
|
//
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
// of this software and associated documentation files (the "Software"), to
|
// of this software and associated documentation files (the "Software"), to
|
||||||
@@ -44,75 +44,95 @@ namespace GameRes.Formats.Ivory
|
|||||||
public override bool IsHierarchic { get { return true; } }
|
public override bool IsHierarchic { get { return true; } }
|
||||||
public override bool CanWrite { get { return false; } }
|
public override bool CanWrite { get { return false; } }
|
||||||
|
|
||||||
|
public PakOpener ()
|
||||||
|
{
|
||||||
|
Signatures = new uint[] { 0x204B5066, 0x324B5066 };
|
||||||
|
}
|
||||||
|
|
||||||
public override ArcFile TryOpen (ArcView file)
|
public override ArcFile TryOpen (ArcView file)
|
||||||
{
|
{
|
||||||
if (file.MaxOffset != file.View.ReadUInt32 (4))
|
int version = '2' == file.View.ReadByte (3) ? 2 : 1;
|
||||||
return null;
|
|
||||||
|
|
||||||
long base_offset = 0;
|
long base_offset = 0;
|
||||||
List<Entry> dir = null;
|
List<Entry> dir = null;
|
||||||
bool got_names = false;
|
byte[] names = null;
|
||||||
long offset = 8;
|
using (var stream = file.CreateStream())
|
||||||
while (offset < file.MaxOffset)
|
|
||||||
{
|
{
|
||||||
var id = new AsciiString (file.View.ReadBytes (offset, 4));
|
Func<IBinaryStream, long> read_long;
|
||||||
uint section_size = file.View.ReadUInt32 (offset+4);
|
if (2 == version)
|
||||||
if (0 == section_size)
|
read_long = s => s.ReadInt64();
|
||||||
|
else
|
||||||
|
read_long = s => s.ReadUInt32();
|
||||||
|
|
||||||
|
stream.Position = 4;
|
||||||
|
if (file.MaxOffset != read_long (stream))
|
||||||
return null;
|
return null;
|
||||||
uint header_size = file.View.ReadUInt32 (offset+8);
|
for (;;)
|
||||||
if ("cLST" == id)
|
|
||||||
{
|
{
|
||||||
int count = file.View.ReadInt32 (offset+0x10);
|
long section_start = stream.Position;
|
||||||
if (!IsSaneCount (count))
|
var id_bytes = stream.ReadBytes (4);
|
||||||
|
if (0 == id_bytes.Length)
|
||||||
|
break;
|
||||||
|
var id = new AsciiString (id_bytes);
|
||||||
|
var section_size = read_long (stream);
|
||||||
|
var header_size = read_long (stream);
|
||||||
|
if (section_size < 4 || header_size > section_size)
|
||||||
return null;
|
return null;
|
||||||
uint key = file.View.ReadUInt32 (offset+0x14);
|
var content_pos = section_start + header_size;
|
||||||
var clst = file.View.ReadBytes (offset+header_size, section_size - header_size);
|
if ("cLST" == id)
|
||||||
Decrypt (clst, key);
|
|
||||||
dir = new List<Entry> (count);
|
|
||||||
int index_offset = 0;
|
|
||||||
for (int i = 0; i < count; ++i)
|
|
||||||
{
|
{
|
||||||
var entry = new PkEntry {
|
stream.ReadUInt32();
|
||||||
NameOffset = LittleEndian.ToInt32 (clst, index_offset),
|
int count = stream.ReadInt32();
|
||||||
Offset = LittleEndian.ToUInt32 (clst, index_offset+4),
|
if (!IsSaneCount (count))
|
||||||
Size = LittleEndian.ToUInt32 (clst, index_offset+8),
|
return null;
|
||||||
};
|
uint key = stream.ReadUInt32();
|
||||||
dir.Add (entry);
|
stream.Position = content_pos;
|
||||||
index_offset += 12;
|
var clst = stream.ReadBytes ((int)(section_size - header_size));
|
||||||
|
Decrypt (clst, key);
|
||||||
|
dir = new List<Entry> (count);
|
||||||
|
using (var index = new BinMemoryStream (clst))
|
||||||
|
{
|
||||||
|
for (int i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
var entry = new PkEntry {
|
||||||
|
NameOffset = (int)read_long (index),
|
||||||
|
Offset = (long)read_long (index),
|
||||||
|
Size = (uint)read_long (index),
|
||||||
|
};
|
||||||
|
dir.Add (entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
else if ("cNAM" == id)
|
||||||
else if ("cNAM" == id)
|
|
||||||
{
|
|
||||||
if (null == dir)
|
|
||||||
return null;
|
|
||||||
uint key = file.View.ReadUInt32 (offset+0x10);
|
|
||||||
var cnam = file.View.ReadBytes (offset+header_size, section_size - header_size);
|
|
||||||
Decrypt (cnam, key);
|
|
||||||
foreach (PkEntry entry in dir)
|
|
||||||
{
|
{
|
||||||
var name = Binary.GetCString (cnam, entry.NameOffset);
|
if (null == dir)
|
||||||
entry.Name = name;
|
return null;
|
||||||
if (name.HasExtension (".px"))
|
stream.ReadUInt32();
|
||||||
entry.Type = "audio";
|
uint key = stream.ReadUInt32();
|
||||||
else
|
stream.Position = content_pos;
|
||||||
entry.Type = FormatCatalog.Instance.GetTypeFromName (name);
|
names = stream.ReadBytes ((int)(section_size - header_size));
|
||||||
|
Decrypt (names, key);
|
||||||
}
|
}
|
||||||
got_names = true;
|
else if ("cDAT" == id)
|
||||||
|
{
|
||||||
|
base_offset = content_pos;
|
||||||
|
}
|
||||||
|
stream.Position = section_start + section_size;
|
||||||
}
|
}
|
||||||
else if ("cDAT" == id)
|
|
||||||
{
|
|
||||||
base_offset = offset + header_size;
|
|
||||||
}
|
|
||||||
offset += section_size;
|
|
||||||
}
|
}
|
||||||
if (null == dir || !got_names || 0 == base_offset)
|
if (null == dir || null == names || 0 == base_offset)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
foreach (var entry in dir)
|
foreach (PkEntry entry in dir)
|
||||||
{
|
{
|
||||||
entry.Offset += base_offset;
|
entry.Offset += base_offset;
|
||||||
if (!entry.CheckPlacement (file.MaxOffset))
|
if (!entry.CheckPlacement (file.MaxOffset))
|
||||||
return null;
|
return null;
|
||||||
|
var name = Binary.GetCString (names, entry.NameOffset);
|
||||||
|
entry.Name = name;
|
||||||
|
if (name.HasExtension (".px"))
|
||||||
|
entry.Type = "audio";
|
||||||
|
else
|
||||||
|
entry.Type = FormatCatalog.Instance.GetTypeFromName (name);
|
||||||
}
|
}
|
||||||
return new ArcFile (file, this, dir);
|
return new ArcFile (file, this, dir);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user