implemented 'non color' ARC archives.

This commit is contained in:
morkt 2016-05-20 04:12:23 +04:00
parent f4517d4183
commit 2b41686e3f
8 changed files with 377 additions and 3 deletions

View File

@ -98,6 +98,12 @@
<Compile Include="Liar\ImageLIM.cs" />
<Compile Include="MnoViolet\ImageDIF.cs" />
<Compile Include="NitroPlus\ArcNPK.cs" />
<Compile Include="NonColor\ArcDAT.cs" />
<Compile Include="Crc64.cs" />
<Compile Include="NonColor\WidgetNCARC.xaml.cs">
<DependentUpon>WidgetNCARC.xaml</DependentUpon>
</Compile>
<Compile Include="RealLive\ArcG00.cs" />
<Compile Include="RealLive\ArcOVK.cs" />
<Compile Include="RealLive\AudioNWA.cs" />
<Compile Include="RealLive\ImageG00.cs" />
@ -293,6 +299,16 @@
<Compile Include="ShiinaRio\ArcS25.cs" />
<Compile Include="ArcSAF.cs" />
<Compile Include="BlackCyc\ArcVPK.cs" />
<Compile Include="WebP\Alpha.cs" />
<Compile Include="WebP\Decoder.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="WebP\Filters.cs" />
<Compile Include="WebP\Huffman.cs" />
<Compile Include="WebP\ImageWEBP.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="WebP\Lossless.cs" />
<Compile Include="Will\ArcPNA.cs" />
<Compile Include="Will\ArcPulltop.cs" />
<Compile Include="Xuse\ArcBIN.cs" />
@ -518,6 +534,10 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="NonColor\WidgetNCARC.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="NScripter\CreateONSWidget.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
@ -615,7 +635,6 @@
</EmbeddedResource>
<EmbeddedResource Include="Strings\arcStrings.ru-RU.resx" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PreBuildEvent>perl "$(SolutionDir)inc-revision.pl" "$(ProjectPath)" $(ConfigurationName)

View File

@ -0,0 +1,280 @@
//! \file ArcDAT.cs
//! \date Sat May 14 02:20:37 2016
//! \brief 'non color' resource archive.
//
// 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;
using GameRes.Formats.Properties;
using GameRes.Formats.Strings;
namespace GameRes.Formats.NonColor
{
internal class ArcDatEntry : PackedEntry
{
public byte[] RawName;
public ulong Hash;
public int Flags;
}
internal class ArcDatArchive : ArcFile
{
public readonly ulong MasterKey;
public ArcDatArchive (ArcView arc, ArchiveFormat impl, ICollection<Entry> dir, ulong key)
: base (arc, impl, dir)
{
MasterKey = key;
}
}
[Serializable]
public class Scheme
{
public string Title;
public ulong Hash;
public Scheme(string title)
{
Title = title;
var key = Encodings.cp932.GetBytes(title);
Hash = Crc64.Compute(key, 0, key.Length);
}
}
[Serializable]
public class ArcDatScheme : ResourceScheme
{
public Dictionary<string, Scheme> KnownSchemes;
public static ulong GetKey (string title)
{
var key = Encodings.cp932.GetBytes (title);
return Crc64.Compute (key, 0, key.Length);
}
}
public class ArcDatOptions : ResourceOptions
{
public string Scheme;
}
[Export(typeof(ArchiveFormat))]
public class DatOpener : ArchiveFormat
{
public override string Tag { get { return "ARC/noncolor"; } }
public override string Description { get { return "'non color' resource archive"; } }
public override uint Signature { get { return 0; } }
public override bool IsHierarchic { get { return true; } }
public override bool CanCreate { get { return false; } }
public DatOpener ()
{
Extensions = new string[] { "dat" };
}
public static readonly string PersistentFileMapName = "NCFileMap.dat";
public override ArcFile TryOpen (ArcView file)
{
if (!file.Name.EndsWith (".dat", StringComparison.InvariantCultureIgnoreCase))
return null;
int count = file.View.ReadInt32 (0) ^ 0x26ACA46E;
if (!IsSaneCount (count))
return null;
var scheme = QueryScheme();
if (null == scheme)
return null;
var file_map = ReadFilenameMap (scheme);
uint index_offset = 4;
var dir = new List<Entry> (count);
for (int i = 0; i < count; ++i)
{
ulong hash = file.View.ReadUInt64 (index_offset);
int flags = file.View.ReadByte (index_offset+8) ^ (byte)hash;
uint offset = file.View.ReadUInt32 (index_offset+9) ^ (uint)hash;
uint size = file.View.ReadUInt32 (index_offset+0xD) ^ (uint)hash;
uint unpacked_size = file.View.ReadUInt32 (index_offset+0x11) ^ (uint)hash;
index_offset += 0x15;
string name;
byte[] raw_name = null;
if (file_map.TryGetValue (hash, out raw_name))
{
name = Encodings.cp932.GetString (raw_name);
}
else if (2 == flags)
{
name = hash.ToString ("X8");
}
else
{
continue;
}
if (flags != 2)
{
offset ^= raw_name[raw_name.Length >> 1];
size ^= raw_name[raw_name.Length >> 2];
unpacked_size ^= raw_name[raw_name.Length >> 3];
}
var entry = new ArcDatEntry {
Name = name,
Type = FormatCatalog.Instance.GetTypeFromName (name),
RawName = raw_name,
Hash = hash,
Flags = flags,
Offset = offset,
Size = size,
UnpackedSize = unpacked_size,
IsPacked = 2 == flags,
};
if (!entry.CheckPlacement (file.MaxOffset))
return null;
dir.Add (entry);
}
return new ArcDatArchive (file, this, dir, scheme.Hash);
}
public override Stream OpenEntry (ArcFile arc, Entry entry)
{
var darc = arc as ArcDatArchive;
var dent = entry as ArcDatEntry;
if (null == darc || null == dent || 0 == dent.Flags || 0 == dent.Size)
return base.OpenEntry (arc, entry);
var data = arc.File.View.ReadBytes (entry.Offset, entry.Size);
if (2 == dent.Flags)
{
if (darc.MasterKey != 0)
{
unsafe
{
fixed (byte* data8 = data)
{
uint key = (uint)(dent.Hash ^ darc.MasterKey);
uint* data32 = (uint*)data8;
for (int i = data.Length/4; i > 0; --i)
*data32++ ^= key;
}
}
}
return new ZLibStream (new MemoryStream (data), CompressionMode.Decompress);
}
// 1 == dent.Flags
int block_length = data.Length / dent.RawName.Length;
int n = 0;
for (int i = 0; i < dent.RawName.Length-1; ++i)
for (int j = 0; j < block_length; ++j)
data[n++] ^= dent.RawName[i];
return new MemoryStream (data);
}
static IDictionary<ulong, Tuple<uint, int>> FileMapIndex = null;
internal IDictionary<ulong, Tuple<uint, int>> ReadIndex (BinaryReader idx)
{
int scheme_count = idx.ReadInt32();
idx.BaseStream.Seek (12, SeekOrigin.Current);
var map = new Dictionary<ulong, Tuple<uint, int>> (scheme_count);
for (int i = 0; i < scheme_count; ++i)
{
ulong key = idx.ReadUInt64();
uint offset = idx.ReadUInt32();
int count = idx.ReadInt32();
map[key] = Tuple.Create (offset, count);
}
return map;
}
Tuple<ulong, Dictionary<ulong, byte[]>> LastAccessedScheme;
internal IDictionary<ulong, byte[]> ReadFilenameMap (Scheme scheme)
{
if (null != LastAccessedScheme && LastAccessedScheme.Item1 == scheme.Hash)
return LastAccessedScheme.Item2;
var dir = Path.GetDirectoryName (System.Reflection.Assembly.GetExecutingAssembly().Location);
var lst_file = Path.Combine (dir, PersistentFileMapName);
var idx_file = Path.ChangeExtension (lst_file, ".idx");
using (var idx_stream = File.OpenRead (idx_file))
using (var idx = new BinaryReader (idx_stream))
{
if (null == FileMapIndex)
FileMapIndex = ReadIndex (idx);
Tuple<uint, int> nc_info;
if (!FileMapIndex.TryGetValue (scheme.Hash, out nc_info))
throw new UnknownEncryptionScheme();
using (var lst_stream = File.OpenRead (lst_file))
using (var lst = new BinaryReader (lst_stream))
{
var name_map = new Dictionary<ulong, byte[]> (nc_info.Item2);
idx_stream.Position = nc_info.Item1;
for (int i = 0; i < nc_info.Item2; ++i)
{
ulong key = idx.ReadUInt64();
uint offset = idx.ReadUInt32();
int length = idx.ReadInt32();
lst_stream.Position = offset;
name_map[key] = lst.ReadBytes (length);
}
LastAccessedScheme = Tuple.Create (scheme.Hash, name_map);
return name_map;
}
}
}
public static Dictionary<string, Scheme> KnownSchemes = new Dictionary<string, Scheme>();
public override ResourceScheme Scheme
{
get { return new ArcDatScheme { KnownSchemes = KnownSchemes }; }
set { KnownSchemes = ((ArcDatScheme)value).KnownSchemes; }
}
Scheme QueryScheme ()
{
var options = Query<ArcDatOptions> (arcStrings.ArcEncryptedNotice);
Scheme scheme;
if (string.IsNullOrEmpty (options.Scheme) || !KnownSchemes.TryGetValue (options.Scheme, out scheme))
return null;
return scheme;
}
public override ResourceOptions GetDefaultOptions ()
{
return new ArcDatOptions { Scheme = Settings.Default.NCARCScheme };
}
public override object GetAccessWidget ()
{
return new GUI.WidgetNCARC();
}
}
}

View File

@ -0,0 +1,12 @@
<StackPanel x:Class="GameRes.Formats.GUI.WidgetNCARC"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:p="clr-namespace:GameRes.Formats.Properties"
MaxWidth="250" Orientation="Vertical">
<ComboBox Name="Scheme" ItemsSource="{Binding}"
SelectedValue="{Binding Source={x:Static p:Settings.Default}, Path=NCARCScheme, Mode=TwoWay}" Width="200"
SelectedValuePath="Key" DisplayMemberPath="Key" HorizontalAlignment="Left"/>
<TextBox Name="Original" Background="Transparent" BorderThickness="0" Text="{Binding Path=Value.Title}"
IsReadOnly="True" TextWrapping="NoWrap" Grid.Row="1" Margin="0,3,0,3" HorizontalAlignment="Left"
DataContext="{Binding ElementName=Scheme, Path=SelectedItem}"/>
</StackPanel>

View File

@ -0,0 +1,18 @@
using System.Windows.Controls;
using System.Linq;
using GameRes.Formats.NonColor;
namespace GameRes.Formats.GUI
{
/// <summary>
/// Interaction logic for WidgetNCARC.xaml
/// </summary>
public partial class WidgetNCARC : StackPanel
{
public WidgetNCARC()
{
InitializeComponent();
Scheme.ItemsSource = DatOpener.KnownSchemes.OrderBy (x => x.Key);
}
}
}

View File

@ -525,5 +525,17 @@ namespace GameRes.Formats.Properties {
this["AGSTitle"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
public string NCARCScheme {
get {
return ((string)(this["NCARCScheme"]));
}
set {
this["NCARCScheme"] = value;
}
}
}
}

View File

@ -128,5 +128,8 @@
<Setting Name="AGSTitle" Type="System.String" Scope="User">
<Value Profile="(Default)" />
</Setting>
<Setting Name="NCARCScheme" Type="System.String" Scope="User">
<Value Profile="(Default)" />
</Setting>
</Settings>
</SettingsFile>

View File

@ -130,6 +130,9 @@
<setting name="AGSTitle" serializeAs="String">
<value />
</setting>
<setting name="NCARCScheme" serializeAs="String">
<value />
</setting>
</GameRes.Formats.Properties.Settings>
</userSettings>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/></startup></configuration>

View File

@ -108,6 +108,7 @@ Ai Suru Tsuma, Misaki no Furin Shouko<br/>
Amber Quartz<br/>
Arpeggio ~Kimi Iro no Melody~<br/>
Chikan Kizoku<br/>
Futagoza no Paradox<br/>
Narimono<br/>
Reconquista<br/>
White ~blanche comme la lune~<br/>
@ -155,6 +156,7 @@ Umineko<br/>
</td></tr>
<tr><td>*.pac</td><td><tt>PAC</tt></td><td>No</td><td>NeXAS</td><td>
Baldr Sky DiveX<br/>
Fossette ~Cafe au Le Ciel Bleu~<br/>
Jinki Extend Re:Vision<br/>
Maji de Watashi ni Koishinasai!<br/>
</td></tr>
@ -193,6 +195,7 @@ Fairytale Requiem<br/>
Love Negotiator<br/>
Sekien no Inganock<br/>
Shikkoku no Sharnoth<br/>
Yami no Sen Ou ~Seijo Ojoku~<br/>
</td></tr>
<tr class="odd"><td>*.lwg</td><td><tt>LG</tt></td><td>No</td></tr>
<tr class="odd"><td>*.wcg</td><td><tt>WGq</tt></td><td>Yes</td></tr>
@ -218,10 +221,12 @@ Mayoeru Futari to Sekai no Subete<br/>
Mahoutsukai no Yoru<br/>
Nakadashi Hara Maid series<br/>
Natsupochi<br/>
Natsuzora Kanata<br/>
Nidaime wa ☆ Mahou Shoujo<br/>
Nuki Doki!<br/>
Okiba ga Nai!<br/>
Oku-sama wa Moto Yariman<br/>
Omana 2: Omaenchi Moeteruzo<br/>
Ore no Saimin Fantasia<br/>
RGH ~Koi to Hero to Gakuen to~<br/>
Riding Incubus<br/>
@ -265,6 +270,7 @@ Shoujo Senki Soul Eater<br/>
<tr><td>*.dat</td><td>-</td><td>No</td><td rowspan="2">M no Violet</td><td rowspan="2">Nanase Ren</td></tr>
<tr><td>*</td><td><tt>gra</tt><br/><tt>mas</tt><br/><tt>dif</tt></td><td>No</td></tr>
<tr class="odd"><td>*.ald</td><td>-</td><td>No</td><td rowspan="4">Alice Soft</td><td rowspan="4">
Pastel Chime 3 Bind Seeker<br/>
Shaman's Sanctuary -Miko no Seiiki-<br/>
Tsuma Shibori<br/>
</td></tr>
@ -293,6 +299,7 @@ Mechiku ~Injoku no Shuuyoujo~<br/>
Momo x Momi<br/>
Michibikareshi Mono-tachi no Rakuen ~BEDLAM~<br/>
Onsen Kankou Yukemuri Chijou<br/>
Oshiete! Bloomer Sensei<br/>
Ryoujoku Costume Play<br/>
Seikoujo Claudia<br/>
Taijoku no Ori<br/>
@ -408,6 +415,7 @@ Itazura ZERO<br>
<tr class="odd"><td>*.noa<br/>*.dat</td><td><tt>Entis\x1a</tt></td><td>No</td><td rowspan="2">Entis GLS</td><td rowspan="2">
Alea Akaki Tsuki o Haruka ni Nozomi<br/>
Iroha ~Aki no Yuuhi ni Kagefumi o~<br/>
Gap P<br/>
Konneko<br/>
Natsu no Ame<br/>
Nerawareta Megami Tenshi Angeltia<br/>
@ -441,6 +449,7 @@ X Change 2<br/>
X Change 2R<br/>
Eve to Iu Na no Omocha<br/>
Hissatsu Chikannin II<br/>
Otomegari<br/>
Ryoujoku Gojuusou<br/>
Tokumei Sentai Sirenger<br/>
Tokumei Sentai Yuzu Ranger<br/>
@ -452,6 +461,7 @@ Zetsuboushi<br/>
<tr class="odd"><td>*.zbm<br/>*.cwl</td><td><tt>SZDD</tt></td><td>No</td></tr>
<tr><td>*.pack</td><td><tt>FilePackVer1.0</tt><br/><tt>FilePackVer2.0</tt><br/><tt>FilePackVer3.0</tt></td><td>No</td><td rowspan="3">QLIE</td><td rowspan="3">
Bishoujo Mangekyou -Kami ga Tsukuritamouta Shoujo-tachi-<br/>
Hidamari Basket<br/>
Makai Tenshi Djibril -episode 3-<br/>
Mehime no Toriko<br/>
Nanatsu no Fushigi no Owaru Toki<br/>
@ -546,7 +556,8 @@ Vampire Crusaders<br/>
<tr><td>*.gpk+*.gtb<br/>*.vpk+*.vtb</td><td>-</td><td>No</td><td rowspan="3">Black Cyc</td><td rowspan="3">
Before Dawn Daybreak ~Shinen no Utahime~<br/>
Gun-Katana<br/>
Yami no Koe Zero<br/>
Kurogane no Tsubasa ~The Alchemist's Story~<br/>
Yami no Koe series<br/>
</td></tr>
<tr><td>*.dwq</td><td><tt>BMP</tt><br/><tt>JPEG</tt><br/><tt>PNG</tt><br/><tt>JPEG+MASK</tt><br/><tt>PACKBMP+MASK</tt><br/></td><td>No</td></tr>
<tr><td>*.vaw<br/>*.wgq</td><td><tt>IF PACKTYPE==</tt><br/><tt>OGG</tt></td><td>No</td></tr>
@ -629,6 +640,7 @@ Shukufuku no Kane no Oto wa, Sakurairo no Kaze to Tomo ni<br/>
</td></tr>
<tr class="odd"><td>*.bsa</td><td><tt>BSArc</tt></td><td>No</td><td rowspan="2">Bishop</td><td rowspan="2">
Houkago ~Nureta Seifuku~<br/>
Kyouiku Shidou<br/>
Yakata ~Kannou Kitan~<br/>
</td></tr>
<tr class="odd"><td>*.bsg</td><td><tt>BSS-Graphics</tt><br/><tt>BSS-Composition</tt></td><td>No</td></tr>
@ -698,6 +710,7 @@ Haruiro Ouse<br/>
</td></tr>
<tr><td>*.pb3</td><td><tt>PB3B</tt></td><td>No</td></tr>
<tr class="odd"><td>*.g2<br/>*.stx</td><td>-</td><td>No</td><td rowspan="2">GLib2</td><td rowspan="2">
Hikikomori Muke Hitozuma-sensei<br/>
Hitozuma Net Auction<br/>
</td></tr>
<tr class="odd"><td>*.pgx</td><td><tt>PGX</tt></td><td>No</td></tr>
@ -717,17 +730,22 @@ Paimega<br/>
</td></tr>
<tr class="odd"><td>*.snn+*.inx</td><td>-</td><td>No</td><td rowspan="2">BlueGale</td><td rowspan="2">
Cafe Junkie<br/>
Immoral<br/>
Majidashi! Royale ~Finish wa Watashi no Naka de~<br/>
MILK Junkies<br/>
</td></tr>
<tr class="odd"><td>*.zbm</td><td><tt>amp_</tt></td><td>No</td></tr>
<tr><td>*.vfs</td><td><tt>VF</tt></td><td>No</td><td rowspan="4">Aoi</td><td rowspan="4">
Alfred Gakuen Mamono Daitai<br/>
Brown Doori Sanbanme<br/>
Daisounan<br/>
Dancing Crazies<br/>
Level Justice<br/>
Ouzoku<br/>
</td></tr>
<tr><td>*.iph</td><td><tt>RIFF....IPH fmt</tt></td><td>No</td></tr>
<tr><td>*.aog</td><td><tt>AoiOgg</tt></td><td>No</td></tr>
<tr><td>*.box</td><td><tt>AOIBX10</tt><br/><tt>AOIBOX7</tt></td><td>No</td></tr>
<tr><td>*.box</td><td><tt>AOIBOX5</tt><br/><tt>AOIBOX7</tt><br/><tt>AOIBX10</tt><br/><tt>AOIBX12</tt><br/><tt>AOIMY01</tt></td><td>No</td></tr>
<tr class="odd"><td>*.gd+*.dll</td><td>-</td><td>No</td><td>Xuse</td><td>
Eien no Aselia -The Spirit of Eternity Sword-
</td></tr>
@ -777,12 +795,14 @@ Angenehm Platz -Kleiner Garten Sie Erstellen-<br/>
</td></tr>
<tr><td>*.eme</td><td><tt>RREDATA</tt></td><td>No</td><td>Emon Engine</td><td>
Ase Nure Shoujo Misaki "Anata no Nioi de Icchau!"<br/>
D-spray Biyaku de Motemote Kachou Dairi Hosa<br/>
Hitomi no Rakuin ~Inbaku no Mesu Dorei~<br/>
</td></tr>
<tr class="odd"><td>*.grp</td><td>-</td><td>No</td><td>Ankh</td><td>
Mozu<br/>
</td></tr>
<tr><td>*.gpc</td><td><tt>Gpc7</tt></td><td>No</td><td>Super NekoX</td><td>
Jorou Gumo ~Makotogatari~<br/>
Sister Contrast!
</td></tr>
<tr class="odd"><td>*.psb</td><td><tt>PSB</tt></td><td>No</td><td>E-mote</td><td>
@ -792,6 +812,7 @@ Angenehm Platz -Kleiner Garten Sie Erstellen-<br/>
Sweet ~Hanjuku na Tenshi-tachi~<br/>
</td></tr>
<tr class="odd"><td>*.ovk</td><td>-</td><td>No</td><td rowspan="4">RealLive</td><td rowspan="4">
Gakuen Taima! Holy x Moly<br/>
Joi-san no Iitsuke!!<br/>
Shiawase na Ohime-sama<br/>
</td></tr>
@ -802,6 +823,12 @@ Shiawase na Ohime-sama<br/>
Valkyrie Complex<br/>
</td></tr>
<tr><td>*.cps</td><td>-</td><td>No</td></tr>
<tr class="odd"><td>arc*.dat<br/>script.dat</td><td>-</td><td>No</td><td>non color</td><td>
Doubly na Kanojo<br/>
Nora to Oujo to Noraneko Heart<br/>
Tsujidou-san no Jun'ai Road<br/>
Tsujidou-san no Virgin Road<br/>
</td></tr>
</table>
<p><a name="note-1" class="footnote">1</a> Non-encrypted only</p>
</body>