();
+
+ public override ResourceScheme Scheme
+ {
+ get { return new TinkAudioScheme { KnownKeys = KnownKeys }; }
+ set { KnownKeys = ((TinkAudioScheme)value).KnownKeys; }
+ }
+
+ public override SoundInput TryOpen (Stream file)
+ {
+ var header = new byte[Math.Min (0xE1F, file.Length)];
+ if (0x10 != file.Read (header, 0, 0x10))
+ return null;
+ var signature = LittleEndian.ToUInt32 (header, 0);
+ byte[] key;
+ if (!KnownKeys.TryGetValue (signature, out key))
+ {
+ signature = LittleEndian.ToUInt32 (header, 0xC);
+ if (!KnownKeys.TryGetValue (signature, out key))
+ return null;
+ file.Read (header, 4, 0xC);
+ }
+ header[0] = (byte)'O';
+ header[1] = (byte)'g';
+ header[2] = (byte)'g';
+ header[3] = (byte)'S';
+ file.Read (header, 0x10, header.Length-0x10);
+ int k = 0;
+ for (int i = 4; i < header.Length; ++i)
+ {
+ header[i] ^= key[k++];
+ if (k >= key.Length)
+ k = 1;
+ }
+ Stream input;
+ if (header.Length >= file.Length)
+ input = new MemoryStream (header);
+ else
+ input = new PrefixStream (header, new StreamRegion (file, file.Position));
+ var sound = OggAudio.Instance.TryOpen (input);
+ if (sound != null && header.Length >= file.Length)
+ file.Dispose();
+ return sound;
+ }
+ }
+}
diff --git a/ArcFormats/Cyberworks/ImageTINK.cs b/ArcFormats/Cyberworks/ImageTINK.cs
new file mode 100644
index 00000000..10115cda
--- /dev/null
+++ b/ArcFormats/Cyberworks/ImageTINK.cs
@@ -0,0 +1,265 @@
+//! \file ImageTINK.cs
+//! \date Fri Jun 17 18:49:04 2016
+//! \brief Tinker Bell encrypted image file.
+//
+// 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;
+
+namespace GameRes.Formats.Cyberworks
+{
+ public enum AImageHeader
+ {
+ Flags = 0,
+ Field1 = 1,
+ Field2 = 2,
+ Height = 3,
+ Width = 4,
+ UnpackedSize = 5,
+ AlphaSize = 6,
+ BitsSize = 7,
+ }
+
+ internal sealed class AImageReader : IDisposable
+ {
+ public readonly ImageMetaData Info = new ImageMetaData();
+
+ BinaryReader m_input;
+ byte[] m_output;
+ AImageScheme m_scheme;
+
+ public byte[] Data { get { return m_output; } }
+
+ public AImageReader (Stream input, AImageScheme scheme)
+ {
+ m_input = new ArcView.Reader (input);
+ m_scheme = scheme;
+ }
+
+ public void Unpack ()
+ {
+ var header = new int[m_scheme.HeaderOrder.Length];
+ for (int i = 0; i < m_scheme.HeaderOrder.Length; ++i)
+ {
+ int b = GetInt();
+ header[m_scheme.HeaderOrder[i]] = b;
+ }
+ Info.Width = (uint)header[4];
+ Info.Height = (uint)header[3];
+ if (0 == Info.Width || Info.Width >= 0x8000 || 0 == Info.Height || Info.Height >= 0x8000)
+ throw new InvalidFormatException();
+ int unpacked_size = header[5];
+ if (unpacked_size <= 0)
+ throw new InvalidFormatException();
+ int flags = header[0];
+ int bits_size = header[7];
+ int data_offset = bits_size * 2;
+ if (0 == flags)
+ CopyV0 (unpacked_size);
+ else if (2 == (flags & 6))
+ UnpackV2 (bits_size, data_offset);
+ else if (6 == (flags & 6))
+ {
+ if (0 == bits_size)
+ CopyV6 (unpacked_size, header[6]);
+ else
+ UnpackV6 (bits_size, data_offset, data_offset + header[6]);
+ }
+ else
+ throw new InvalidFormatException();
+ }
+
+ void CopyV0 (int data_size)
+ {
+ int plane_size = (int)Info.Width * (int)Info.Height;
+ if (plane_size == data_size)
+ {
+ Info.BPP = 8;
+ m_output = m_input.ReadBytes (data_size);
+ }
+ else if (3 * plane_size == data_size)
+ {
+ Info.BPP = 24;
+ m_output = m_input.ReadBytes (data_size);
+ }
+ else if (4 * plane_size == data_size)
+ {
+ Info.BPP = 32;
+ m_output = m_input.ReadBytes (data_size);
+ }
+ else
+ {
+ Info.BPP = 24;
+ int dst_stride = (int)Info.Width * 3;
+ int src_stride = (dst_stride + 3) & ~3;
+ if (src_stride * (int)Info.Height != data_size)
+ throw new InvalidFormatException();
+ m_output = new byte[dst_stride * (int)Info.Height];
+ int dst = 0;
+ for (uint y = 0; y < Info.Height; ++y)
+ {
+ m_input.Read (m_output, dst, dst_stride);
+ dst += dst_stride;
+ m_input.BaseStream.Seek (src_stride-dst_stride, SeekOrigin.Current);
+ }
+ }
+ }
+
+ void UnpackV2 (int offset1, int rgb_offset)
+ {
+ Info.BPP = 24;
+ var rgb_map = m_input.ReadBytes (offset1);
+ var alpha_map = m_input.ReadBytes (rgb_offset-offset1);
+ int plane_size = (int)Info.Width * (int)Info.Height;
+ m_output = new byte[plane_size * 3];
+
+ int bit = 1;
+ int bit_src = 0;
+ int dst = 0;
+ for (int i = 0; i < plane_size; ++i)
+ {
+ if ((bit & alpha_map[bit_src]) == 0 && (bit & rgb_map[bit_src]) != 0)
+ {
+ m_input.Read (m_output, dst, 3);
+ }
+ dst += 3;
+ if (0x80 == bit)
+ {
+ ++bit_src;
+ bit = 1;
+ }
+ else
+ bit <<= 1;
+ }
+ }
+
+ void CopyV6 (int alpha_size, int rgb_size)
+ {
+ Info.BPP = 32;
+ int plane_size = (int)Info.Width * (int)Info.Height;
+ m_output = new byte[plane_size * 4];
+ int stride = ((int)Info.Width * 3 + 3) & ~3;
+ var line = new byte[stride];
+ int dst = 3;
+ for (uint y = 0; y < Info.Height; ++y)
+ {
+ m_input.Read (line, 0, stride);
+ int src = 0;
+ for (uint x = 0; x < Info.Width; ++x)
+ {
+ m_output[dst] = line[src];
+ dst += 4;
+ src += 3;
+ }
+ }
+ dst = 0;
+ for (uint y = 0; y < Info.Height; ++y)
+ {
+ m_input.Read (line, 0, stride);
+ int src = 0;
+ for (uint x = 0; x < Info.Width; ++x)
+ {
+ m_output[dst ] = line[src++];
+ m_output[dst+1] = line[src++];
+ m_output[dst+2] = line[src++];
+ dst += 4;
+ }
+ }
+ }
+
+ void UnpackV6 (int offset1, int alpha_offset, int rgb_offset)
+ {
+ Info.BPP = 32;
+ var rgb_map = m_input.ReadBytes (offset1);
+ var alpha_map = m_input.ReadBytes (alpha_offset - offset1);
+ var alpha = m_input.ReadBytes (rgb_offset - alpha_offset);
+ int plane_size = (int)Info.Width * (int)Info.Height;
+ m_output = new byte[plane_size * 4];
+
+ int bit = 1;
+ int bit_src = 0;
+ int alpha_src = 0;
+ int dst = 0;
+ for (int i = 0; i < plane_size; ++i)
+ {
+ bool has_alpha = (bit & alpha_map[bit_src]) != 0;
+ if (has_alpha || (bit & rgb_map[bit_src]) != 0)
+ {
+ m_input.Read (m_output, dst, 3);
+ if (has_alpha)
+ {
+ m_output[dst+3] = alpha[alpha_src];
+ alpha_src += 3;
+ }
+ else
+ m_output[dst+3] = 0xFF;
+ }
+ dst += 4;
+ if (0x80 == bit)
+ {
+ ++bit_src;
+ bit = 1;
+ }
+ else
+ bit <<= 1;
+ }
+ }
+
+ int GetInt ()
+ {
+ byte a = m_input.ReadByte();
+ if (a == m_scheme.Value3)
+ a = 0;
+ int d = 0;
+ int c = 0;
+ for (;;)
+ {
+ byte a1 = m_input.ReadByte();
+ if (a1 == m_scheme.Value2)
+ break;
+ if (a1 != m_scheme.Value1)
+ {
+ c = (a1 == m_scheme.Value3) ? 0 : a1;
+ }
+ else
+ {
+ ++d;
+ }
+ }
+ return a + (c + d * m_scheme.Value1) * m_scheme.Value1;
+ }
+
+ #region IDisposable Members
+ bool _disposed = false;
+ public void Dispose ()
+ {
+ if (!_disposed)
+ {
+ m_input.Dispose();
+ _disposed = true;
+ }
+ }
+ #endregion
+ }
+}
diff --git a/ArcFormats/Cyberworks/WidgetBELL.xaml b/ArcFormats/Cyberworks/WidgetBELL.xaml
new file mode 100644
index 00000000..b3cc313f
--- /dev/null
+++ b/ArcFormats/Cyberworks/WidgetBELL.xaml
@@ -0,0 +1,7 @@
+
+
+
diff --git a/ArcFormats/Cyberworks/WidgetBELL.xaml.cs b/ArcFormats/Cyberworks/WidgetBELL.xaml.cs
new file mode 100644
index 00000000..35ef3f1f
--- /dev/null
+++ b/ArcFormats/Cyberworks/WidgetBELL.xaml.cs
@@ -0,0 +1,22 @@
+using System.Linq;
+using System.Windows.Controls;
+using GameRes.Formats.Cyberworks;
+using GameRes.Formats.Strings;
+
+namespace GameRes.Formats.GUI
+{
+ ///
+ /// Interaction logic for WidgetBELL.xaml
+ ///
+ public partial class WidgetBELL : StackPanel
+ {
+ public WidgetBELL()
+ {
+ InitializeComponent();
+ var keys = new string[] { arcStrings.ArcIgnoreEncryption };
+ Title.ItemsSource = keys.Concat (DatOpener.KnownSchemes.Keys.OrderBy (x => x));
+ if (-1 == Title.SelectedIndex)
+ Title.SelectedIndex = 0;
+ }
+ }
+}
diff --git a/ArcFormats/Properties/Settings.Designer.cs b/ArcFormats/Properties/Settings.Designer.cs
index b4075d35..b820742d 100644
--- a/ArcFormats/Properties/Settings.Designer.cs
+++ b/ArcFormats/Properties/Settings.Designer.cs
@@ -573,5 +573,17 @@ namespace GameRes.Formats.Properties {
this["MGPKTitle"] = value;
}
}
+
+ [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("")]
+ public string BELLTitle {
+ get {
+ return ((string)(this["BELLTitle"]));
+ }
+ set {
+ this["BELLTitle"] = value;
+ }
+ }
}
}
diff --git a/ArcFormats/Properties/Settings.settings b/ArcFormats/Properties/Settings.settings
index 26898952..16dc5afc 100644
--- a/ArcFormats/Properties/Settings.settings
+++ b/ArcFormats/Properties/Settings.settings
@@ -140,5 +140,8 @@
+
+
+
\ No newline at end of file
diff --git a/ArcFormats/app.config b/ArcFormats/app.config
index 24f0e518..fe5f6783 100644
--- a/ArcFormats/app.config
+++ b/ArcFormats/app.config
@@ -142,6 +142,9 @@
+
+
+
diff --git a/supported.html b/supported.html
index 9603273d..a705bd52 100644
--- a/supported.html
+++ b/supported.html
@@ -556,6 +556,7 @@ Sora no Iro, Mizu no Iro
Thunder Claps!
Tokumei Kyoushi Hitomi
Toshiue Lesson ~Mama to Oba-san to Sensei to~
+Tutorial Summer
| *.iks | NPSR | No | X[iks] | Shikkan ~Hazukashimerareta Karada, Oreta Kokoro~ |
| *.wbp | ARCFORM3 WBUG | No | Wild Bug |
@@ -932,6 +933,12 @@ Natsunone -Ring-
Cartagra
Kara no Shoujo 2
|
+
data.NN ArcNN.dat | - | No | TinkerBell |
+Hime Kami 1/2
+Oshioki ~Gakuen Reijou Kousei Keikaku~
+Ore Maou! ~Kudake Chitta Tamashii
+Zoku Etsuraku no Tane
+ |
Non-encrypted only