diff --git a/ArcFormats/ArcFormats.csproj b/ArcFormats/ArcFormats.csproj index 307be2a7..86d58d8e 100644 --- a/ArcFormats/ArcFormats.csproj +++ b/ArcFormats/ArcFormats.csproj @@ -146,6 +146,8 @@ + + diff --git a/ArcFormats/NekoSDK/ArcDAT.cs b/ArcFormats/NekoSDK/ArcDAT.cs new file mode 100644 index 00000000..0f223f8b --- /dev/null +++ b/ArcFormats/NekoSDK/ArcDAT.cs @@ -0,0 +1,95 @@ +//! \file ArcDAT.cs +//! \date Tue Aug 02 12:02:04 2016 +//! \brief NekoSDK resource archives. +// +// 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; +using System.Collections.Generic; +using System.ComponentModel.Composition; +using System.IO; +using GameRes.Compression; +using GameRes.Utility; + +namespace GameRes.Formats.NekoSDK +{ + [Export(typeof(ArchiveFormat))] + public class DatOpener : ArchiveFormat + { + public override string Tag { get { return "DAT/NekoSDK"; } } + public override string Description { get { return "NekoSDK engine resource archive"; } } + public override uint Signature { get { return 0; } } + public override bool IsHierarchic { get { return false; } } + public override bool CanCreate { get { return false; } } + + public DatOpener () + { + Extensions = new string[] { "dat" }; + } + + public override ArcFile TryOpen (ArcView file) + { + uint first_offset = file.View.ReadUInt32 (0x88) ^ 0xCACACAu; + if (first_offset <= 0 || first_offset >= file.MaxOffset) + return null; + int count = (int)first_offset / 0x8C; + if (first_offset != count * 0x8C) + return null; + if (!IsSaneCount (--count)) + return null; + + uint index_offset = 0; + var dir = new List (count); + var name_buffer = new byte[0x80]; + for (int i = 0; i < count; ++i) + { + file.View.Read (index_offset, name_buffer, 0, 0x80); + if (0 == name_buffer[0]) + return null; + var name = Binary.GetCString (name_buffer, 0, name_buffer.Length); + var entry = FormatCatalog.Instance.Create (name); + entry.UnpackedSize = file.View.ReadUInt32 (index_offset+0x80) ^ 0xCACACAu; + entry.Size = file.View.ReadUInt32 (index_offset+0x84) ^ 0xCACACAu; + entry.Offset = file.View.ReadUInt32 (index_offset+0x88) ^ 0xCACACAu; + if (entry.Offset < first_offset || !entry.CheckPlacement (file.MaxOffset)) + return null; + entry.IsPacked = entry.UnpackedSize != 0; + if (!entry.IsPacked) + entry.UnpackedSize = entry.Size; + index_offset += 0x8C; + dir.Add(entry); + } + if (0 == dir.Count) + return null; + return new ArcFile (file, this, dir); + } + + public override Stream OpenEntry (ArcFile arc, Entry entry) + { + var input = arc.File.CreateStream (entry.Offset, entry.Size); + var pent = entry as PackedEntry; + if (null == pent || !pent.IsPacked) + return input; + return new LzssStream (input); + } + } +} diff --git a/ArcFormats/NekoSDK/ImageALP.cs b/ArcFormats/NekoSDK/ImageALP.cs new file mode 100644 index 00000000..ce323688 --- /dev/null +++ b/ArcFormats/NekoSDK/ImageALP.cs @@ -0,0 +1,69 @@ +//! \file ImageALP.cs +//! \date Tue Aug 02 15:35:56 2016 +//! \brief NekoSDK BMP alpha-channel extension. +// +// 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; +using System.ComponentModel.Composition; +using System.IO; +using System.Windows.Media; + +namespace GameRes.Formats.NekoSDK +{ + [Export(typeof(IBmpExtension))] + public class AlpBitmap : IBmpExtension + { + public ImageData Read (Stream file, BmpMetaData info) + { + if (info.BPP != 24 && info.BPP != 32 || !file.CanSeek) + return null; + var alp_name = Path.ChangeExtension (info.FileName, "alp"); + if (alp_name.Equals (info.FileName, StringComparison.InvariantCultureIgnoreCase) + || !VFS.FileExists (alp_name)) + return null; + var alpha_size = info.Width * info.Height; + var alpha = new byte[alpha_size]; + using (var alp = VFS.OpenStream (alp_name)) + { + if (alpha.Length != alp.Read (alpha, 0, alpha.Length) || alp.ReadByte() != -1) + return null; + } + file.Position = info.HeaderLength; + int dst_stride = (int)info.Width * 4; + var pixels = new byte[(int)info.Height * dst_stride]; + int src_pixel_size = info.BPP / 8; + int dst = (int)(info.Height-1) * dst_stride; + for (int y = (int)info.Height-1; y >= 0; --y) + { + int a_src = (int)info.Width * y; + for (int x = 0; x < dst_stride; x += 4) + { + file.Read (pixels, dst+x, src_pixel_size); + pixels[dst+x+3] = alpha[a_src++]; + } + dst -= dst_stride; + } + return ImageData.Create (info, PixelFormats.Bgra32, null, pixels, dst_stride); + } + } +} diff --git a/supported.html b/supported.html index 3d2913cb..3fa1103a 100644 --- a/supported.html +++ b/supported.html @@ -284,7 +284,10 @@ Soukan Yuugi 2
*.bmd_BMDYes *.asd-No -*.dat-YesStudio e.go!Men at Work 2 +*.dat-YesStudio e.go! +Men at Work 2
+Natsu Kagura
+ *.mbl-NoMarble Assault Angel Canon
Chikatetsu Fuusa Jiken
@@ -388,6 +391,7 @@ Zansho Omimai MoushiagemasuShiinaRio v2.41
*.padPADNo *ARC2
ARC1NoAST Bokura wa Piacere
+Hokenshitsu no Sensei ~Onedari Bakunyuu Lesson~
Jokyoushi wo Kurau
Lovers Collection
Nachtmusik
@@ -770,6 +774,8 @@ Izumo
Izumo 2
Izumo 2 ~Gakuen Kyousoukyoku~
Izumo 3
+Oni Kagura
+Tsuki Kagura
*.pbxPandora.boxNoTerios Ikinari Happy Bell
@@ -908,6 +914,7 @@ Sweet ~Hanjuku na Tenshi-tachi~
Gakuen Taima! Holy x Moly
Joi-san no Iitsuke!!
Shiawase na Ohime-sama
+Shin Genre Esudere!!
*.nwa-No *.g00-No @@ -965,6 +972,8 @@ Cartagra
Kara no Shoujo 2
data.NN
ArcNN.dat-NoCyberworks +Aniyome Kyouka-san to Sono Haha Chikako-san
+Aru Kazoku no Kankeizu
Cosplay Ecchi ~Layer Kana no Yuuutsu~
Hanamaru! 2
Hime Kami 1/2
@@ -995,6 +1004,9 @@ Soushinjutsu Plus
*.ns2-NoNScripter Rakuin Hime Runed Princess
+*.dat-NoNekoSDK +Elevator Panic ~Misshitsu no Inkou~
+

1 Non-encrypted only