From f6b729e5d95cac180cff2ad6e5804e876a448803 Mon Sep 17 00:00:00 2001 From: morkt Date: Mon, 5 Sep 2016 07:39:39 +0400 Subject: [PATCH] (FPK): support archives with encrypted index. --- ArcFormats/Interheart/ArcFPK.cs | 61 ++++++++++++++++++++++++++++----- supported.html | 8 ++++- 2 files changed, 60 insertions(+), 9 deletions(-) diff --git a/ArcFormats/Interheart/ArcFPK.cs b/ArcFormats/Interheart/ArcFPK.cs index 2aea1e91..2871448f 100644 --- a/ArcFormats/Interheart/ArcFPK.cs +++ b/ArcFormats/Interheart/ArcFPK.cs @@ -2,7 +2,7 @@ //! \date Mon May 25 10:01:24 2015 //! \brief FPK resource archives implementation. // -// Copyright (C) 2015 by morkt +// Copyright (C) 2015-2016 by morkt // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to @@ -42,17 +42,29 @@ namespace GameRes.Formats.CandySoft public override ArcFile TryOpen (ArcView file) { - int count = file.View.ReadInt32 (0); - if (!IsSaneCount (count)) + if (file.MaxOffset < 0x10) return null; + int count = file.View.ReadInt32 (0); List dir = null; - try + if (count < 0) { - dir = ReadIndex (file, count, 0x10); + count &= 0x7FFFFFFF; + if (!IsSaneCount (count)) + return null; + dir = ReadEncryptedIndex (file, count); + } + else + { + if (!IsSaneCount (count)) + return null; + try + { + dir = ReadIndex (file, count, 0x10); + } + catch { /* read failed, try another filename length */ } + if (null == dir) + dir = ReadIndex (file, count, 0x18); } - catch { /* read failed, try another filename length */ } - if (null == dir) - dir = ReadIndex (file, count, 0x18); if (null == dir) return null; return new ArcFile (file, this, dir); @@ -81,6 +93,39 @@ namespace GameRes.Formats.CandySoft return dir; } + private List ReadEncryptedIndex (ArcView file, int count) + { + file.View.Reserve (file.MaxOffset-8, 8); + uint index_offset = file.View.ReadUInt32 (file.MaxOffset-4); + if (index_offset < 4 || index_offset >= file.MaxOffset-8) + return null; + var key = file.View.ReadBytes (file.MaxOffset-8, 4); + int name_size = 0x18; + int index_size = count * (12 + name_size); + var index = file.View.ReadBytes (index_offset, (uint)index_size); + if (index.Length != index_size) + return null; + for (int i = 0; i < index.Length; ++i) + index[i] ^= key[i & 3]; + + int index_pos = 0; + var dir = new List (count); + for (int i = 0; i < count; ++i) + { + string name = Binary.GetCString (index, index_pos+8, name_size); + if (string.IsNullOrWhiteSpace (name)) + return null; + var entry = FormatCatalog.Instance.Create (name); + entry.Offset = LittleEndian.ToUInt32 (index, index_pos); + entry.Size = LittleEndian.ToUInt32 (index, index_pos+4); + if (!entry.CheckPlacement (file.MaxOffset)) + return null; + dir.Add (entry); + index_pos += 12 + name_size; + } + return dir; + } + public override Stream OpenEntry (ArcFile arc, Entry entry) { var input = arc.File.CreateStream (entry.Offset, entry.Size); diff --git a/supported.html b/supported.html index e64a0ae8..8ce44fed 100644 --- a/supported.html +++ b/supported.html @@ -134,6 +134,7 @@ White ~blanche comme la lune~
*.datNEKOPACKNoRosebleu
Lime Inpyuri -Hito to Anata to Ayakashi to-
Nostradamus ni Kiitemiro♪
+Tiny Dungeon ~BLACK and WHITE~
*.dat-NoMeteor
Silver Bullet Chokotto☆Vampire!
@@ -486,6 +487,7 @@ Tsuribaka ~Gakuen Taikou! Joshikousei Tsuriage Adventure~
*.gr-No *.datSPackNoGoku-FeroInchuu Reiki Elenova *.fpk-NoCandy Soft
Interheart +Aimai Ren'ai
Chijoku no Kankei ~Inkou Kyoushi~
Chijoku no Kankei 2
Jii -Nozoki no Houshuu-
@@ -1071,13 +1073,17 @@ Caramel Box Yarukibako
Kagiroi ~Shaku Kei~
L.i.n.k.
-*.lacLACNoLeaf +*.lacLACNoLeaf +Kimi ga Yobu, Megiddo no Oka de
ToHeart2 AnotherDays
*.a\x1E\xAFNo *.amam00No *.g-No *.w-No +*.pakLACNo +*.texTEX PACK0.02No +*.lgflgfNo *.ark-NoIrrlicht Alter Ego