Compare commits

...

25 Commits

Author SHA1 Message Date
Crsky
848a3a7b17 Add support "Ore no Hitomi de Maruhadaka! Fukachi na Mirai to Misukasu Vision" 2023-08-06 06:14:09 +08:00
Crsky
fb543fd3bc Added support "11eyes -Resona Forma-" 2023-08-06 06:07:39 +08:00
Crsky
1b30bb8249 Add support "Rui wa Tomo o Yobu -Full Voice Edition-" 2023-06-30 19:33:43 +08:00
Crsky
1aa985dffd Add support "Mashiro-iro Symphony -Love is pure white- Remake for FHD" 2023-06-27 20:52:34 +08:00
Crsky
ba1f807157 Add support "Mashiro-iro Symphony: Sana Edition" 2023-06-27 20:45:13 +08:00
Crsky
c8a20e0d3d Add support "AMBITIOUS MISSION After Episode 1" 2023-05-30 21:28:33 +08:00
Crsky
c6c46ce30e Add support "Criminal Border: 2nd offence" 2023-05-30 21:03:25 +08:00
Crsky
dd3d706919 Add support "Koi de wa Naku - It's not love, but so where near." 2023-03-04 12:11:08 +08:00
Crsky
00490899e3 (Kirikiri): Add Syangrila Smart encryption 2023-03-04 12:08:47 +08:00
Crsky
845e99f433 Add support "Café Stella to Shinigami no Chou [Steam]" 2023-01-29 18:18:22 +08:00
Crsky
c6d8e7c423 Add support "D.C.5 ~Da Capo 5~" 2023-01-29 16:53:27 +08:00
Crsky
1648a7a4f4 Changed package version 2023-01-29 15:53:51 +08:00
crskycode
c278e48615 Add support "9-nine- Deluxe Edition" 2023-01-23 19:48:51 +08:00
Crsky
1ab7087fe7 (SakanaGL): support new version 2023-01-09 16:31:09 +08:00
Crsky
99778823f1 Add support "Futamata Ren'ai - Yua & Kirame Mini After Story" 2023-01-08 19:43:12 +08:00
Crsky
ea84d6cc19 Add support "Futamata Ren'ai - Rui & Miyako Mini After Story" 2023-01-08 19:42:08 +08:00
Crsky
da25246c69 Add support "Futamata Ren'ai" 2023-01-08 19:40:46 +08:00
Crsky
9f5f96dd64 Fix assembly redirect problem 2023-01-08 18:47:45 +08:00
Crsky
c40996a775 Merge branch 'master' of https://github.com/crskycode/GARbro 2023-01-08 18:32:04 +08:00
Crsky
7e4f35163d Merge pull request #7 from h1531095/master
Bug: path not resolved before file check
2023-01-08 18:28:39 +08:00
Crsky
26129650fb Add support "Motto! Haramase! Honoo no Oppai Isekai Oppai Maid Gakuen!" 2023-01-08 18:22:30 +08:00
h1531095
7d0cc66090 Bug: path not resolved before file check 2023-01-05 15:19:52 +08:00
Crsky
9e0909ff0c Add support "Manakashi no Yuri wa Akaku Somaru [DL]" 2022-12-20 21:58:52 +08:00
Crsky
73f16aff26 (Kaguya): implemented AF01 archive. 2022-12-18 03:27:19 +08:00
Crsky
b06648783f Add support "Koikishi Purely Kiss" 2022-12-08 13:54:37 +08:00
10 changed files with 222 additions and 16 deletions

View File

@@ -228,6 +228,7 @@
<Compile Include="Interheart\ArcFPK2.cs" />
<Compile Include="Interheart\ImageCandy.cs" />
<Compile Include="Ivory\ArcSG.cs" />
<Compile Include="Kaguya\ArcAF.cs" />
<Compile Include="Kaguya\ArcPL00.cs" />
<Compile Include="Kaguya\ArcPL10.cs" />
<Compile Include="Kaguya\ArcPLT.cs" />

View File

@@ -73,10 +73,9 @@ namespace GameRes.Formats.Emote
var match = PathRe.Match (line);
if (!match.Success)
return null;
var pak_name = match.Groups[1].Value;
var pak_name = VFS.CombinePath (dir, match.Groups[1].Value);
if (!VFS.FileExists (pak_name))
return null;
pak_name = VFS.CombinePath (dir, pak_name);
layers.Add (Tuple.Create (pak_name, match.Groups[2].Value));
}
if (0 == layers.Count)

133
ArcFormats/Kaguya/ArcAF.cs Normal file
View File

@@ -0,0 +1,133 @@
//! \file ArcAF.cs
//! \date Sun Apr 02 09:01:51 2017
//! \brief Atelier Kaguya resource archive.
//
// Copyright (C) 2017 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;
namespace GameRes.Formats.Kaguya
{
[Export(typeof(ArchiveFormat))]
public class AfOpener : ArchiveFormat
{
public override string Tag { get { return "ARC/AF01"; } }
public override string Description { get { return "Atelier Kaguya resource archive"; } }
public override uint Signature { get { return 0x31304641; } } // 'AF01'
public override bool IsHierarchic { get { return true; } }
public override bool CanWrite { get { return false; } }
const int MaxFileNameLength = 0x100;
public override ArcFile TryOpen (ArcView file)
{
uint index_offset = file.View.ReadUInt32 (8);
if (index_offset >= file.MaxOffset - 8)
return null;
using (var index = file.CreateStream (index_offset + 8))
{
long data_offset = 12;
var name_buffer = new byte[MaxFileNameLength];
var dir = new List<Entry>();
while (index.PeekByte() != -1)
{
int name_length = index.ReadInt32();
if (name_length <= 0 || name_length > name_buffer.Length)
return null;
if (name_length != index.Read (name_buffer, 0, name_length))
return null;
var name = DecryptString (name_buffer, name_length);
name = name.TrimStart ('\\', '/');
var entry = FormatCatalog.Instance.Create<PackedEntry> (name);
int flags = index.ReadInt16();
entry.IsPacked = 1 == flags;
data_offset += 4 + name_length + 6;
if (entry.IsPacked)
data_offset += 4;
entry.Offset = data_offset;
entry.Size = index.ReadUInt32();
entry.UnpackedSize = index.ReadUInt32();
if (!entry.IsPacked)
entry.Size = entry.UnpackedSize;
if (!entry.CheckPlacement (file.MaxOffset))
return null;
dir.Add (entry);
data_offset += entry.Size;
}
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 arc.File.CreateStream (entry.Offset, entry.Size);
using (var input = arc.File.CreateStream (entry.Offset, entry.Size))
{
var output = new byte[pent.UnpackedSize];
LzUnpack (input, output);
return new BinMemoryStream (output);
}
}
string DecryptString (byte[] name, int length)
{
for (int i = 0; i < length; ++i)
name[i] ^= 0xFF;
return Encodings.cp932.GetString (name, 0, length);
}
void LzUnpack (Stream input, byte[] output)
{
var frame = new byte[0x1000];
int frame_pos = 1;
int dst = 0;
using (var bits = new MsbBitStream (input))
{
while (dst < output.Length)
{
if (0 != bits.GetNextBit ())
{
byte b = (byte)bits.GetBits (8);
output[dst++] = b;
frame[frame_pos++ & 0xFFF] = b;
}
else
{
int offset = bits.GetBits (12);
int count = bits.GetBits (4) + 2;
for (int i = 0; i < count; ++i)
{
byte b = frame[(offset + i) & 0xFFF];
output[dst++] = b;
frame[frame_pos++ & 0xFFF] = b;
}
}
}
}
}
}
}

View File

@@ -1513,4 +1513,46 @@ namespace GameRes.Formats.KiriKiri
}
}
}
[Serializable]
public class SyangrilaSmartCrypt : ICrypt
{
byte[] GetKey (uint hash)
{
return new byte[5]
{
(byte)(hash >> 5),
(byte)(hash >> 5),
(byte)(hash >> 7),
(byte)(hash >> 1),
(byte)(hash >> 4),
};
}
public override byte Decrypt (Xp3Entry entry, long offset, byte value)
{
var key = GetKey (entry.Hash);
if (offset <= 0x64)
return (byte)(value ^ key[4]);
else
return (byte)(value ^ key[offset & 3]);
}
public override void Decrypt (Xp3Entry entry, long offset, byte[] buffer, int pos, int count)
{
var key = GetKey (entry.Hash);
for (var i = 0; i < count; i++)
{
if (offset+i <= 0x64)
buffer[pos+i] ^= key[4];
else
buffer[pos+i] ^= key[(offset+i) & 3];
}
}
public override void Encrypt (Xp3Entry entry, long offset, byte[] buffer, int pos, int count)
{
Decrypt (entry, offset, buffer, pos, count);
}
}
}

View File

Binary file not shown.

View File

@@ -28,17 +28,25 @@ using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.IO;
using System.Linq;
using System.Text;
namespace GameRes.Formats.Sakana
{
internal class SxEntry : PackedEntry
{
public int Storage;
public ushort Flags;
public bool IsEncrypted { get { return 0 == (Flags & 0x10); } }
}
internal class SxStorage
{
public uint Size;
public ulong Timestamp;
}
[Export(typeof(ArchiveFormat))]
public class SxOpener : ArchiveFormat
{
@@ -52,9 +60,7 @@ namespace GameRes.Formats.Sakana
public override ArcFile TryOpen (ArcView file)
{
var base_name = Path.GetFileName (file.Name);
var sx_name = base_name.Substring (0, 4) + "(00).sx";
sx_name = VFS.ChangeFileName (file.Name, sx_name);
var sx_name = FindSxName (file.Name);
if (!VFS.FileExists (sx_name) || file.Name.Equals (sx_name, StringComparison.InvariantCultureIgnoreCase))
return null;
byte[] index_data;
@@ -140,6 +146,20 @@ namespace GameRes.Formats.Sakana
}
}
}
internal static string FindSxName(string name)
{
var base_name = Path.GetFileName (name);
var file_name = Path.GetFileNameWithoutExtension (base_name);
for (var i = 1; i <= file_name.Length; i++)
{
var sx_name = file_name.Substring (0, i) + "(00).sx";
sx_name = VFS.ChangeFileName (name, sx_name);
if (VFS.FileExists (sx_name))
return sx_name;
}
return name;
}
}
internal class SxIndexDeserializer
@@ -170,36 +190,47 @@ namespace GameRes.Formats.Sakana
m_dir = new List<Entry> (count);
for (int i = 0; i < count; ++i)
{
m_index.ReadUInt16();
m_index.ReadByte();
int storage = m_index.ReadByte();
ushort flags = Binary.BigEndian (m_index.ReadUInt16());
uint offset = Binary.BigEndian (m_index.ReadUInt32());
uint size = Binary.BigEndian (m_index.ReadUInt32());
var entry = new SxEntry {
Storage = storage,
Flags = flags,
Offset = (long)offset << 4,
Size = size,
IsPacked = 0 != (flags & 0x03),
};
if (!entry.CheckPlacement (m_max_offset))
return null;
m_dir.Add (entry);
}
count = Binary.BigEndian (m_index.ReadUInt16());
var storages = new List<SxStorage>(count);
for (int i = 0; i < count; ++i)
{
m_index.ReadUInt32();
m_index.ReadUInt32();
m_index.ReadUInt32();
Binary.BigEndian (m_index.ReadUInt32()); // archive body length
m_index.ReadUInt64();
m_index.Seek (16, SeekOrigin.Current); // MD5 sum
var storage = new SxStorage {
Size = Binary.BigEndian (m_index.ReadUInt32()) << 4,
Timestamp = Binary.BigEndian (m_index.ReadUInt64()),
};
storages.Add (storage);
m_index.Seek (16, SeekOrigin.Current); // MD5
}
count = Binary.BigEndian (m_index.ReadUInt16());
if (count > 0)
m_index.Seek (count * 24, SeekOrigin.Current);
DeserializeTree();
// Remove entries in other archives
// Note using file size as archive identification can be problematic, but faster than MD5
var current_storage = storages.FindIndex (s => m_max_offset == s.Size);
if (-1 != current_storage)
{
m_dir = m_dir.Where (e => e.CheckPlacement (m_max_offset) && (e as SxEntry).Storage == current_storage).ToList();
}
return m_dir;
}

View File

@@ -100,7 +100,7 @@
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
<bindingRedirect oldVersion="4.0.4.1" newVersion="6.0.0.0"/>
<bindingRedirect oldVersion="4.0.4.1" newVersion="4.0.5.0"/>
</dependentAssembly>
</assemblyBinding>
</runtime>

View File

@@ -7,7 +7,7 @@
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
<bindingRedirect oldVersion="0.0.0.0-4.0.5.0" newVersion="4.0.5.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Buffers" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />

View File

@@ -45,8 +45,8 @@
<Reference Include="System.Numerics.Vectors, Version=4.1.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=4.0.5.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.4.6.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
</Reference>
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />

View File

@@ -3,5 +3,5 @@
<package id="System.Buffers" version="4.5.1" targetFramework="net461" />
<package id="System.Memory" version="4.5.4" targetFramework="net461" />
<package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net461" />
<package id="System.Runtime.CompilerServices.Unsafe" version="6.0.0" targetFramework="net461" />
<package id="System.Runtime.CompilerServices.Unsafe" version="4.6.0" targetFramework="net461" />
</packages>