From 3664e9f0a76a08f705e767da0c436cf4fbb698a8 Mon Sep 17 00:00:00 2001 From: morkt Date: Fri, 20 May 2016 03:55:08 +0400 Subject: [PATCH] (BoxOpener): various versions support. --- ArcFormats/Aoi/ArcBOX.cs | 119 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 117 insertions(+), 2 deletions(-) diff --git a/ArcFormats/Aoi/ArcBOX.cs b/ArcFormats/Aoi/ArcBOX.cs index 7b6c1752..11c90083 100644 --- a/ArcFormats/Aoi/ArcBOX.cs +++ b/ArcFormats/Aoi/ArcBOX.cs @@ -27,6 +27,7 @@ using System.Collections.Generic; using System.ComponentModel.Composition; using System.IO; using System.Security.Cryptography; +using GameRes.Utility; namespace GameRes.Formats.Aoi { @@ -50,19 +51,44 @@ namespace GameRes.Formats.Aoi public override bool IsHierarchic { get { return false; } } public override bool CanCreate { get { return false; } } + static readonly Dictionary VersionKeyMap = new Dictionary { + { 5, 0xAD }, + { 6, 0xB4 }, + { 7, 0xB4 }, + { 10, 0xB2 }, + { 12, 0xA5 }, + }; + public override ArcFile TryOpen (ArcView file) { int version; if (file.View.AsciiEqual (4, "X10")) version = 10; + else if (file.View.AsciiEqual (4, "X12")) + version = 12; else if (file.View.AsciiEqual (4, "OX7\0")) version = 7; + else if (file.View.AsciiEqual (4, "OX6\0")) + version = 6; + else if (file.View.AsciiEqual (4, "OX5 ")) + version = 5; else return null; int count = file.View.ReadInt32 (8); if (!IsSaneCount (count)) return null; + List dir; + if (version > 5) + dir = ReadIndexV6 (file, count); + else + dir = ReadIndexV5 (file, count); + if (null == dir) + return null; + return new BoxArchive (file, this, dir, VersionKeyMap[version]); + } + List ReadIndexV6 (ArcView file, int count) + { int index_offset = 0x10; var dir = new List (count); for (int i = 0; i < count; ++i) @@ -78,8 +104,30 @@ namespace GameRes.Formats.Aoi dir.Add (entry); index_offset += 0x18; } - byte key = 7 == version ? (byte)0xB4 : (byte)0xB2; - return new BoxArchive (file, this, dir, key); + return dir; + } + + List ReadIndexV5 (ArcView file, int count) + { + var base_name = Path.GetFileNameWithoutExtension (file.Name); + int index_offset = 0xC; + uint next_offset = file.View.ReadUInt32 (index_offset); + var dir = new List (count); + for (int i = 0; i < count; ++i) + { + index_offset += 4; + var entry = new Entry { + Name = string.Format ("{0}#{1:D2}.evt", base_name, i), + Type = "script", + Offset = next_offset, + }; + next_offset = i+1 == count ? (uint)file.MaxOffset : file.View.ReadUInt32 (index_offset); + entry.Size = next_offset - (uint)entry.Offset; + if (!entry.CheckPlacement (file.MaxOffset)) + return null; + dir.Add (entry); + } + return dir; } public override Stream OpenEntry (ArcFile arc, Entry entry) @@ -91,4 +139,71 @@ namespace GameRes.Formats.Aoi return new CryptoStream (input, new XorTransform (barc.Key), CryptoStreamMode.Read); } } + + [Export(typeof(ArchiveFormat))] + public class AoiMyOpener : ArchiveFormat + { + public override string Tag { get { return "AOIMY"; } } + public override string Description { get { return "Aoi engine script archive"; } } + public override uint Signature { get { return 0x4D494F41; } } // 'AOIM' + public override bool IsHierarchic { get { return false; } } + public override bool CanCreate { get { return false; } } + + public override ArcFile TryOpen (ArcView file) + { + if (!file.View.AsciiEqual (4, "Y01\0")) + return null; + int count = Binary.BigEndian (file.View.ReadInt32 (8)); + if (!IsSaneCount (count)) + return null; + int index_offset = 0x10; + var dir = new List (count); + for (int i = 0; i < count; ++i) + { + var entry = new Entry { + Name = file.View.ReadString (index_offset, 0x10), + Type = "script", + Offset = Binary.BigEndian (file.View.ReadUInt32 (index_offset+0x10)), + Size = Binary.BigEndian (file.View.ReadUInt32 (index_offset+0x14)), + }; + if (!entry.CheckPlacement (file.MaxOffset)) + return null; + dir.Add (entry); + index_offset += 0x18; + } + return new ArcFile (file, this, dir); + } + + public override Stream OpenEntry (ArcFile arc, Entry entry) + { + var data = arc.File.View.ReadBytes (entry.Offset, entry.Size); + uint offset = (uint)entry.Offset; + for (int i = 0; i < data.Length; ++i) + { + data[i] ^= KeyFromOffset (offset++); + } + return new MemoryStream (data); + } + + static byte KeyFromOffset (uint offset) + { + uint v1 = offset - 0x5CC8E9D7u + (0xA3371629u >> (int)((offset & 0xF) + 1)) - (0x5CC8E9D7u << (int)(31 - (offset & 0xF))); + + uint v3 = v1 << (int)(31 - ((offset >> 4) & 0xF)); + uint v4 = v1 >> (int)(((offset >> 4) & 0xF) + 1); + uint v5 = offset - 0x5CC8E9D7 + + ((offset - 0x5CC8E9D7u + v3 + v4) << (int)(31 - ((offset >> 8) & 0xF))) + + ((offset - 0x5CC8E9D7u + v3 + v4) >> (int)(((offset >> 8) & 0xF) + 1)); + uint v6 = offset - 0x5CC8E9D7u + + (v5 << (int)(31 - ((offset >> 12) & 0xF))) + (v5 >> (int)(((offset >> 12) & 0xF) + 1)); + uint v7 = offset - 0x5CC8E9D7u + + (v6 << (int)(31 - ((offset >> 16) & 0xF))) + (v6 >> (int)(((offset >> 16) & 0xF) + 1)); + int v8 = (int)(offset >> 20) & 0xF; + uint v9 = offset - 0x5CC8E9D7u + + ((offset - 0x5CC8E9D7u + (v7 << (31 - v8)) + (v7 >> (v8 + 1))) << (int)(31 - ((offset >> 24) & 0xF))) + + ((offset - 0x5CC8E9D7u + (v7 << (31 - v8)) + (v7 >> (v8 + 1))) >> (int)(((offset >> 24) & 0xF) + 1)); + uint key = (offset - 0x5CC8E9D7 + (v9 << (int)(31 - (offset >> 28))) + (v9 >> (int)((offset >> 28) + 1))) >> (int)(offset & 0xF); + return (byte)key; + } + } }