diff --git a/ArcFormats/ArcFormats.csproj b/ArcFormats/ArcFormats.csproj index 5051b787..035a837a 100644 --- a/ArcFormats/ArcFormats.csproj +++ b/ArcFormats/ArcFormats.csproj @@ -129,6 +129,7 @@ + diff --git a/ArcFormats/Kaguya/ArcLIN2.cs b/ArcFormats/Kaguya/ArcLIN2.cs new file mode 100644 index 00000000..1e13e185 --- /dev/null +++ b/ArcFormats/Kaguya/ArcLIN2.cs @@ -0,0 +1,144 @@ +//! \file ArcLIN2.cs +//! \date Sun Oct 23 09:57:27 2016 +//! \brief KaGuYa archive format. +// +// Copyright (C) 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 +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +// + +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.IO; +using GameRes.Utility; + +namespace GameRes.Formats.Kaguya +{ + [Export(typeof(ArchiveFormat))] + public class Lin2Opener : ArchiveFormat + { + public override string Tag { get { return "ARC/LIN2"; } } + public override string Description { get { return "KaGuYa script engine resource archive"; } } + public override uint Signature { get { return 0x324E494C; } } // 'LIN2' + public override bool IsHierarchic { get { return false; } } + public override bool CanWrite { get { return false; } } + + public override ArcFile TryOpen (ArcView file) + { + int count = file.View.ReadInt32 (4); + if (!IsSaneCount (count)) + return null; + + uint index_offset = 8; + var name_buffer = new byte[0x100]; + var dir = new List (count); + for (int i = 0; i < count; ++i) + { + ushort name_length = file.View.ReadUInt16 (index_offset); + if (name_length > name_buffer.Length) + name_buffer = new byte[name_length]; + file.View.Read (index_offset+2, name_buffer, 0, name_length); + for (int j = 0; j < name_length; ++j) + name_buffer[j] ^= 0xFF; + var name = Binary.GetCString (name_buffer, 0, name_length); + if (string.IsNullOrEmpty (name)) + return null; + index_offset += 2u + name_length; + var entry = FormatCatalog.Instance.Create (name); + entry.Offset = file.View.ReadUInt32 (index_offset); + entry.Size = file.View.ReadUInt32 (index_offset+4); + if (!entry.CheckPlacement (file.MaxOffset)) + return null; + int type = file.View.ReadInt16 (index_offset+8); + if (1 == type) + entry.IsPacked = true; + else if (2 == type) + entry.Type = "audio"; + dir.Add (entry); + index_offset += 10; + } + return new ArcFile (file, this, dir); + } + + public override Stream OpenEntry (ArcFile arc, Entry entry) + { + var pent = entry as PackedEntry; + if (null == pent || !pent.IsPacked) + return base.OpenEntry (arc, entry); + if (0 == pent.UnpackedSize) + pent.UnpackedSize = arc.File.View.ReadUInt32 (entry.Offset); + using (var input = arc.File.CreateStream (entry.Offset+4, entry.Size-4)) + { + var data = UnpackLzss (input, pent.UnpackedSize); + return new BinMemoryStream (data, entry.Name); + } + } + + byte[] UnpackLzss (IBinaryStream input, uint unpacked_size) + { + var output = new byte[unpacked_size]; + var frame = new byte[0x100]; + int frame_pos = 0xEF; + int dst = 0; + int ctl = 0; + int bit = 0; + int prev_count = 0x100; + while (dst < output.Length) + { + bit >>= 1; + if (0 == bit) + { + ctl = input.ReadByte(); + if (-1 == ctl) + break; + bit = 0x80; + } + if (0 != (ctl & bit)) + { + byte v = input.ReadUInt8(); + frame[frame_pos++ & 0xFF] = v; + output[dst++] = v; + } + else + { + int offset = input.ReadUInt8(); + int count; + if (-1 == prev_count) + { + prev_count = input.ReadUInt8(); + count = prev_count & 0xF; + } + else + { + count = prev_count >> 4; + prev_count = -1; + } + count += 2; + while (count --> 0 && dst < output.Length) + { + byte v = frame[offset++ & 0xFF]; + frame[frame_pos++ & 0xFF] = v; + output[dst++] = v; + } + } + } + return output; + } + } +} diff --git a/ArcFormats/Kaguya/ArcLINK.cs b/ArcFormats/Kaguya/ArcLINK.cs index 0a5dac17..66d89863 100644 --- a/ArcFormats/Kaguya/ArcLINK.cs +++ b/ArcFormats/Kaguya/ArcLINK.cs @@ -50,7 +50,7 @@ namespace GameRes.Formats.Kaguya [Export(typeof(ArchiveFormat))] public class LinkOpener : ArchiveFormat { - public override string Tag { get { return "LINK/KAGUYA"; } } + public override string Tag { get { return "ARC/LINK"; } } public override string Description { get { return "KaGuYa script engine resource archive"; } } public override uint Signature { get { return 0x4B4E494C; } } // 'LINK' public override bool IsHierarchic { get { return false; } } diff --git a/supported.html b/supported.html index 5b8b09e1..d07be64d 100644 --- a/supported.html +++ b/supported.html @@ -81,6 +81,7 @@ Saimin Gakuen
Grisaia no Kajitsu
Happiness! Re:Lucks
Kamikaze ☆ Explorer!
+Koko kara Natsu no Innocence!
Makai Tenshi Djibril -Episode 4-
Sakigake ⇒ Generation!
Sengoku Tenshi Djibril
@@ -139,7 +140,9 @@ White ~blanche comme la lune~
*.datNEKOPACKNoRosebleu
Lime Inpyuri -Hito to Anata to Ayakashi to-
Nostradamus ni Kiitemiro♪
+Tiny Dungeon ~BIRTH for YOURS~
Tiny Dungeon ~BLACK and WHITE~
+Tiny Dungeon ~BLESS of DRAGON~
Tiny Dungeon ~Brave or Slave~
*.dat-NoMeteor
Silver Bullet @@ -392,6 +395,7 @@ Michibikareshi Mono-tachi no Rakuen ~BEDLAM~
Onsen Kankou Yukemuri Chijou
Oshiete! Bloomer Sensei
Ryoujoku Costume Play
+Ryoushuu ~Kinki no Mesuniku Jikken Chousho~
Seikoujo Claudia
Shinshoku
Sweet and Sweet
@@ -430,6 +434,7 @@ Itsuka, Dokoka de ~Ano Ameoto no Kioku~2.36 or 2.37ShiinaRio v2.41
Mahou Shoujo no Taisetsu na Koto ShiinaRio v2.47
Maki Fes! ShiinaRio v2.50
+Mikoko ShiinaRio v2.46
Mimi o Sumaseba ShiinaRio v2.47
Nagagutsu wo Haita Deco ShiinaRio v2.39
Najimi no Oba-chan ShiinaRio v2.47
@@ -765,6 +770,7 @@ Sakimidare
Gigai no Alruna
sys4ini.bin
sys3ini.bin
*.alfS4IC
S3ICNoEushully +Himegari Dungeon Meister
Kuutei Senki ~Tasogare ni Shizumu Kusabi~
Mahou ga Sekai o Sukuimasu
Meishoku no Reiki
@@ -779,6 +785,7 @@ Hyakki Yakou
Mahou Senshi Extra Stage 2 ~Gakuen Kangoku~
Saikyou Goshujin-sama! -Mighty My Master-
Saiminjutsu Re
+Summoner Princess Artemina 2 -Tatakae! Apologue-
Wizard Links
*.medMDNo @@ -806,6 +813,7 @@ Shitai o Arau
Hanikami Clover
Katakoi no Tsuki
Katakoi no Tsuki Extra
+Magica Ride
Shukufuku no Kane no Oto wa, Sakurairo no Kaze to Tomo ni
*.bsaBSArcNoBishop @@ -858,6 +866,7 @@ Genrin no Kishougun
*.mpk-Nopropeller Bullet Butlers
+Kitto, Sumiwataru Asairo Yori mo,
*.mgr-No *.datPAK0NoStudio e.go! @@ -945,11 +954,14 @@ Eien no Aselia -The Spirit of Eternity Sword- Ayakashi
Ayakashi H
-*.arcLINK3NoKaGuYa +*.arcLIN2
LINK3
LINK5
LINK6NoKaGuYa Dokidoki Onee-san
+Harami Tama
Mahokoi ~Ecchi na Mahou de Koi x Koi Shichau~
+Mainichi ga M!
+Ningyou no Yakata
-*.alpAP-2No +*.alpAP-0
AP-2No *.anmAN00No *.pcsPCCSNoC's ware Kuro to Kuro to Kuro no Saidan ~Kodoku~
@@ -966,6 +978,7 @@ Houmon Hanbai ~Otona no Omocha Irimasen ka?~
*.pac-
PACNoUnison Shift
Softpal Maruhi Jinjibu Ryoujokuka
+M.E.s -Doukyuusei Maid Choukyou-
Natsuiro Kokoro Log
Shikotama Slave ~Aruji de Shimai na Tenshi to Akuma~
Unity Marriage ~Futari no Hanayome~
@@ -1090,6 +1103,7 @@ In'youchuu Goku ~Ryoujoku Jigoku Taimaroku~
In'youchuu Kyou ~Ryoujoku Byoutou Taimaroku~
In'youchuu Rei ~Ryoujoku Shiro Taima Emaki~
In'youchuu Shoku ~Ryoushokutou Taimaroku~
+Kairaku Izonshou
Koitsuma Biyori ~Yukino-san wa Hitozuma Kanrinin~
Kowaku no Toki
Kuraibito
@@ -1099,7 +1113,9 @@ Onna Kyoushi Suzune
Ore Maou! ~Kudake Chitta Tamashii
Oshioki ~Gakuen Reijou Kousei Keikaku~
Ouma no Shoku ~Sei ni Tsukaeshi Yami no Guuzou~
+Shukubo no Uzuki ~Hitozuma Miboujin no Nareta Karada to Amai Toiki~
Volley Coaching!
+Yumekoi Tensei
Zoku Etsuraku no Tane
*.binOZNoPatisserie @@ -1197,6 +1213,10 @@ Tiara
*.paz-NoMusica Tsumi no Hikari Rendezvous
+arc.dat-NoAdvSys3 +Okami Tsuma ~Ryokan Baito de no Himitsu~
+ +*.gwdGWDNo

1 Non-encrypted only