From 9d457f99d669143f98f3070c219a6820d55a594c Mon Sep 17 00:00:00 2001 From: morkt Date: Fri, 14 Aug 2015 06:12:35 +0400 Subject: [PATCH] implemented YKC archives and YKG images. --- ArcFormats/ArcFormats.csproj | 2 + ArcFormats/ArcYKC.cs | 84 ++++++++++++++++ ArcFormats/ImageYKG.cs | 135 ++++++++++++++++++++++++++ ArcFormats/Properties/AssemblyInfo.cs | 4 +- supported.html | 4 + 5 files changed, 227 insertions(+), 2 deletions(-) create mode 100644 ArcFormats/ArcYKC.cs create mode 100644 ArcFormats/ImageYKG.cs diff --git a/ArcFormats/ArcFormats.csproj b/ArcFormats/ArcFormats.csproj index 4a31aca5..dd9bed45 100644 --- a/ArcFormats/ArcFormats.csproj +++ b/ArcFormats/ArcFormats.csproj @@ -128,6 +128,7 @@ + @@ -135,6 +136,7 @@ + WidgetRCT.xaml diff --git a/ArcFormats/ArcYKC.cs b/ArcFormats/ArcYKC.cs new file mode 100644 index 00000000..b1766b40 --- /dev/null +++ b/ArcFormats/ArcYKC.cs @@ -0,0 +1,84 @@ +//! \file ArcYKC.cs +//! \date Thu Aug 13 21:52:01 2015 +//! \brief Yuka engine resource archives. +// +// Copyright (C) 2015 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 System.Linq; +using GameRes.Utility; + +namespace GameRes.Formats.Yuka +{ + internal class YukaEntry : Entry + { + public uint NameOffset; + public uint NameLength; + } + + [Export(typeof(ArchiveFormat))] + public class YkcOpener : ArchiveFormat + { + public override string Tag { get { return "YKC"; } } + public override string Description { get { return "Yuka engine resource archive"; } } + public override uint Signature { get { return 0x30434B59; } } // 'YKC0' + public override bool IsHierarchic { get { return true; } } + public override bool CanCreate { get { return false; } } + + public override ArcFile TryOpen (ArcView file) + { + if (0x3130 != file.View.ReadUInt32 (4)) + return null; + uint index_offset = file.View.ReadUInt32 (0x10); + uint index_length = file.View.ReadUInt32 (0x14); + int count = (int)(index_length / 0x14); + if (index_offset >= file.MaxOffset || !IsSaneCount (count)) + return null; + if (index_length > file.View.Reserve (index_offset, index_length)) + return null; + + var dir = new List (count); + for (int i = 0; i < count; ++i) + { + var entry = new YukaEntry(); + entry.NameOffset = file.View.ReadUInt32 (index_offset); + entry.NameLength = file.View.ReadUInt32 (index_offset+4); + entry.Offset = file.View.ReadUInt32 (index_offset+8); + entry.Size = file.View.ReadUInt32 (index_offset+0xC); + if (!entry.CheckPlacement (file.MaxOffset)) + return null; + dir.Add (entry); + index_offset += 0x14; + } + // read in two cycles to avoid memory mapped file page switching when accessing names + foreach (var entry in dir.Cast()) + { + entry.Name = file.View.ReadString (entry.NameOffset, entry.NameLength); + entry.Type = FormatCatalog.Instance.GetTypeFromName (entry.Name); + } + return new ArcFile (file, this, dir); + } + } +} diff --git a/ArcFormats/ImageYKG.cs b/ArcFormats/ImageYKG.cs new file mode 100644 index 00000000..098c8d24 --- /dev/null +++ b/ArcFormats/ImageYKG.cs @@ -0,0 +1,135 @@ +//! \file ImageYKG.cs +//! \date Thu Aug 13 22:16:30 2015 +//! \brief Yuka engine images implementation. +// +// Copyright (C) 2015 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.Linq; +using GameRes.Utility; + +namespace GameRes.Formats.Yuka +{ + internal class YkgMetaData : ImageMetaData + { + public uint DataOffset; + public uint DataSize; + public YkgImage Format; + } + + internal enum YkgImage + { + Bmp, Png, Gnp, + } + + [Export(typeof(ImageFormat))] + public class YkgFormat : ImageFormat + { + public override string Tag { get { return "YKG"; } } + public override string Description { get { return "Yuka engine image format"; } } + public override uint Signature { get { return 0x30474B59; } } // 'YKG0' + + static readonly byte[] PngPrefix = new byte[4] { 0x89, 'P'^0, 'N'^0, 'G'^0 }; + + public override ImageMetaData ReadMetaData (Stream stream) + { + var header = new byte[0x40]; + if (header.Length != stream.Read (header, 0, header.Length)) + return null; + if (!Binary.AsciiEqual (header, 4, "00\0\0")) + return null; + var ykg = new YkgMetaData { + DataOffset = LittleEndian.ToUInt32 (header, 0x28), + DataSize = LittleEndian.ToUInt32 (header, 0x2C) + }; + if (ykg.DataOffset < 0x30) + return null; + ImageMetaData info = null; + using (var img = new StreamRegion (stream, ykg.DataOffset, ykg.DataSize, true)) + { + if (4 != img.Read (header, 0, 4)) + return null; + if (Binary.AsciiEqual (header, "BM")) + { + img.Position = 0; + info = ImageFormat.Bmp.ReadMetaData (img); + ykg.Format = YkgImage.Bmp; + } + else if (Binary.AsciiEqual (header, "\x89PNG")) + { + img.Position = 0; + info = Png.ReadMetaData (img); + ykg.Format = YkgImage.Png; + } + else if (Binary.AsciiEqual (header, "\x89GNP")) + { + using (var body = new StreamRegion (stream, ykg.DataOffset+4, ykg.DataSize-4, true)) + using (var png = new PrefixStream (PngPrefix, body)) + info = Png.ReadMetaData (png); + ykg.Format = YkgImage.Gnp; + } + else + { + return null; + } + } + if (null == info) + return null; + ykg.Width = info.Width; + ykg.Height = info.Height; + ykg.BPP = info.BPP; + ykg.OffsetX = info.OffsetX; + ykg.OffsetY = info.OffsetY; + return ykg; + } + + public override ImageData Read (Stream stream, ImageMetaData info) + { + var meta = info as YkgMetaData; + if (null == meta) + throw new ArgumentException ("YkgFormat.Read should be supplied with YkgMetaData", "info"); + + switch (meta.Format) + { + case YkgImage.Bmp: + using (var bmp = new StreamRegion (stream, meta.DataOffset, meta.DataSize, true)) + return Bmp.Read (bmp, info); + case YkgImage.Png: + using (var png = new StreamRegion (stream, meta.DataOffset, meta.DataSize, true)) + return Png.Read (png, info); + case YkgImage.Gnp: + using (var body = new StreamRegion (stream, meta.DataOffset+4, meta.DataSize-4, true)) + using (var png = new PrefixStream (PngPrefix, body)) + return Png.Read (png, info); + default: + throw new InvalidFormatException(); + } + } + + public override void Write (Stream file, ImageData image) + { + throw new System.NotImplementedException ("YkgFormat.Write not implemented"); + } + } +} diff --git a/ArcFormats/Properties/AssemblyInfo.cs b/ArcFormats/Properties/AssemblyInfo.cs index e05ffc3f..4a13c9ea 100644 --- a/ArcFormats/Properties/AssemblyInfo.cs +++ b/ArcFormats/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion ("1.1.9.91")] -[assembly: AssemblyFileVersion ("1.1.9.91")] +[assembly: AssemblyVersion ("1.1.9.92")] +[assembly: AssemblyFileVersion ("1.1.9.92")] diff --git a/supported.html b/supported.html index 38d77a79..034fb531 100644 --- a/supported.html +++ b/supported.html @@ -322,6 +322,10 @@ Answer Dead
*.arc
*.xarc
*.binMIKO
KOTORINoXuse
ETERNAL Kikouyoku Senki Gin no Toki no Corona
+*.ykcYKC001NoYuka +SuGirly Wish
+ +*.ykgYKG000No

1 Non-encrypted only