diff --git a/ArcFormats/ArcFormats.csproj b/ArcFormats/ArcFormats.csproj
index 02694a65..2f2be9ba 100644
--- a/ArcFormats/ArcFormats.csproj
+++ b/ArcFormats/ArcFormats.csproj
@@ -72,6 +72,7 @@
+
diff --git a/ArcFormats/Banana/ArcPK.cs b/ArcFormats/Banana/ArcPK.cs
index 654324bd..243398f6 100644
--- a/ArcFormats/Banana/ArcPK.cs
+++ b/ArcFormats/Banana/ArcPK.cs
@@ -43,7 +43,7 @@ namespace GameRes.Formats.Banana // namespace is arbitrary, actual format source
public PkOpener ()
{
- Extensions = new string[] { "pk" };
+ Extensions = new string[] { "pk", "dat" };
}
public override ArcFile TryOpen (ArcView file)
diff --git a/ArcFormats/Banana/ImageGEC.cs b/ArcFormats/Banana/ImageGEC.cs
new file mode 100644
index 00000000..941036b8
--- /dev/null
+++ b/ArcFormats/Banana/ImageGEC.cs
@@ -0,0 +1,340 @@
+//! \file ImageGEC.cs
+//! \date Mon Jun 20 15:45:46 2016
+//! \brief Yellow Pig image format.
+//
+// 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;
+using System.Windows.Media;
+using GameRes.Utility;
+
+namespace GameRes.Formats.YellowPig
+{
+ internal class GecMetaData : ImageMetaData
+ {
+ public byte Type;
+ public int DataOffset;
+ public int AlphaOffset;
+ }
+
+ [Export(typeof(ImageFormat))]
+ public class GecFormat : ImageFormat
+ {
+ public override string Tag { get { return "GEC"; } }
+ public override string Description { get { return "Yellow Pig image format"; } }
+ public override uint Signature { get { return 0; } }
+
+ public override ImageMetaData ReadMetaData (Stream stream)
+ {
+ var header = new byte[0x11];
+ if (header.Length != stream.Read (header, 0, header.Length))
+ return null;
+ byte type = header[0];
+ if (type != 0 && type != 1)
+ return null;
+ var info = new GecMetaData
+ {
+ Type = type,
+ OffsetX = LittleEndian.ToInt16 (header, 1),
+ OffsetY = LittleEndian.ToInt16 (header, 3),
+ Width = LittleEndian.ToUInt16 (header, 5),
+ Height = LittleEndian.ToUInt16 (header, 7),
+ BPP = 0 == type ? 24 : 32,
+ AlphaOffset = LittleEndian.ToInt32 (header, 9),
+ DataOffset = LittleEndian.ToInt32 (header, 0xD),
+ };
+ if (info.OffsetX < 0 || info.OffsetY < 0 || info.Width <= 0 || info.Height <= 0
+ || info.DataOffset < 0 || info.DataOffset > stream.Length)
+ return null;
+ if (1 == type && info.AlphaOffset <= 0)
+ return null;
+ return info;
+ }
+
+ public override ImageData Read (Stream stream, ImageMetaData info)
+ {
+ var reader = new GecReader (stream, (GecMetaData)info);
+ reader.Unpack();
+ return ImageData.CreateFlipped (info, reader.Format, null, reader.Data, reader.Stride);
+ }
+
+ public override void Write (Stream file, ImageData image)
+ {
+ throw new NotImplementedException ("GecFormat.Write not implemented");
+ }
+ }
+
+ internal sealed class GecReader
+ {
+ byte[] m_input;
+ byte[] m_output;
+ GecMetaData m_info;
+
+ public PixelFormat Format { get; private set; }
+ public int Stride { get; private set; }
+ public byte[] Data { get { return m_output; } }
+
+ public GecReader (Stream input, GecMetaData info)
+ {
+ m_input = new byte[input.Length];
+ input.Read (m_input, 0, m_input.Length);
+ m_info = info;
+ }
+
+ int m_bits = 0;
+ int m_bits_src = 0;
+ int m_bits_count = 0;
+
+ public void Unpack ()
+ {
+ if (0 == m_info.Type)
+ {
+ UnpackPixels (0x11);
+ Format = PixelFormats.Bgr24;
+ Stride = (int)m_info.Width * 3;
+ }
+ else
+ {
+ UnpackPixels (0x1D);
+ int bits = 0x1D + m_info.AlphaOffset;
+ m_alpha_width = LittleEndian.ToUInt16 (m_input, 0x15);
+ m_alpha_height = LittleEndian.ToUInt16 (m_input, 0x17);
+ int data = bits + LittleEndian.ToInt32 (m_input, 0x19);
+ var alpha = UnpackAlpha (bits, data);
+ ApplyAlpha (alpha);
+ Format = PixelFormats.Bgra32;
+ Stride = (int)m_info.Width * 4;
+ }
+ }
+
+ int m_alpha_width;
+ int m_alpha_height;
+
+ void ApplyAlpha (byte[] alpha)
+ {
+ var image = new byte[m_info.Width * m_info.Height * 4];
+ int src = 0;
+ int a_y = m_alpha_height - (int)m_info.Height - m_info.OffsetY;
+ int a_src = a_y * m_alpha_width + m_info.OffsetX;
+ int dst = 0;
+ for (uint y = 0; y < m_info.Height; ++y)
+ {
+ for (uint x = 0; x < m_info.Width; ++x)
+ {
+ image[dst++] = m_output[src++];
+ image[dst++] = m_output[src++];
+ image[dst++] = m_output[src++];
+ image[dst++] = alpha[a_src+x];
+ }
+ a_src += m_alpha_width;
+ }
+ m_output = image;
+ }
+
+ int m_dst;
+ byte[] m_table = new byte[0x100];
+
+ void UnpackPixels (int bits_src)
+ {
+ m_bits_src = bits_src;
+ m_bits_count = 0;
+ m_output = new byte[(int)m_info.Width * (int)m_info.Height * 3];
+ int src = bits_src + m_info.DataOffset;
+ for (int j = 0; j < 0x100; ++j)
+ m_table[j] = (byte)j;
+ byte[] frame1 = new byte[0x10002];
+ byte[] frame2 = new byte[0x10002];
+ m_dst = 0;
+ while (m_dst < m_output.Length)
+ {
+ int count = Math.Min (m_output.Length - m_dst, 0xFFFF);
+ if (GetNextBit() != 0)
+ {
+ ReadFrame (frame1, count + 2);
+ UnpackFrame1 (frame1, frame2, count + 2);
+ UnpackFrame2 (frame2, 2, count, LittleEndian.ToUInt16 (frame2, 0));
+ }
+ else
+ {
+ src = UnpackRLE (src, count);
+ }
+ }
+ }
+
+ byte[] UnpackAlpha (int bits_src, int data_src)
+ {
+ m_bits_src = bits_src;
+ m_bits_count = 0;
+ var alpha = new byte[m_alpha_height * m_alpha_width];
+ int dst = 0;
+ while (dst < alpha.Length)
+ {
+ if (GetNextBit() != 0)
+ {
+ int count = GetInt();
+ byte v = m_input[data_src++];
+ while (count --> 0)
+ alpha[dst++] = v;
+ }
+ else
+ {
+ alpha[dst++] = m_input[data_src++];
+ }
+ }
+ return alpha;
+ }
+
+ void ReadFrame (byte[] frame, int count) // sub_423990
+ {
+ int j = 0;
+ while (j < count)
+ {
+ if (0 != GetNextBit())
+ {
+ frame[j++] = (byte)GetInt();
+ }
+ else
+ {
+ int n = GetInt();
+ while (n --> 0)
+ frame[j++] = 0;
+ }
+ }
+ }
+
+ void UnpackFrame1 (byte[] frame, byte[] dst, int count) // sub_423670
+ {
+ byte prev = 1;
+ int n = 0;
+ while (count --> 0)
+ {
+ byte v8 = frame[n];
+ byte v9 = m_table[v8];
+ if (1 == v8)
+ {
+ if (prev != 0)
+ {
+ m_table[1] = m_table[0];
+ m_table[0] = v9;
+ }
+ }
+ else if (v8 > 1)
+ {
+ Buffer.BlockCopy (m_table, 1, m_table, 2, v8 - 1);
+ m_table[1] = v9;
+ }
+ dst[n++] = v9;
+ prev = v8;
+ }
+ }
+
+ ushort[] table1 = new ushort[0x100];
+ ushort[] table2 = new ushort[0x100];
+ ushort[] table3 = new ushort[0x10002];
+
+ void UnpackFrame2 (byte[] frame, int src, int count, ushort first) // sub_4236F0
+ {
+ for (int i = 0; i < 0x100; ++i)
+ table1[i] = 0;
+ for (int i = 0; i < count; ++i)
+ ++table1[frame[src+i]];
+ ushort v = 0;
+ for (int i = 0; i < 0x100; i += 1)
+ {
+ table2[i] = v;
+ v += table1[i];
+ table1[i] = 0;
+ }
+ for (int i = 0; i < count; ++i)
+ {
+ int d = frame[src+i];
+ ushort a = table2[d];
+ ushort b = table1[d]++;
+ table3[a + b] = (ushort)i;
+ }
+ ushort next = table3[first];
+ while (count --> 0)
+ {
+ m_output[m_dst++] = frame[src+next];
+ next = table3[next];
+ }
+ }
+
+ int UnpackRLE (int src, int count) // sub_423A10
+ {
+ while (count > 0)
+ {
+ if (0 == GetNextBit())
+ {
+ m_output[m_dst++] = m_input[src++];
+ m_output[m_dst++] = m_input[src++];
+ m_output[m_dst++] = m_input[src++];
+ count -= 3;
+ }
+ else
+ {
+ int n = GetInt() * 3;
+ m_output[m_dst] = m_input[src++];
+ m_output[m_dst+1] = m_input[src++];
+ m_output[m_dst+2] = m_input[src++];
+ Binary.CopyOverlapped (m_output, m_dst, m_dst+3, n-3);
+ m_dst += n;
+ count -= n;
+ }
+ }
+ return src;
+ }
+
+ int GetInt () // sub_423810
+ {
+ int count = 0;
+ while (0 == GetNextBit())
+ {
+ ++count;
+ }
+ int v = 1;
+ while (count > 0)
+ {
+ v = (v << 1) | GetNextBit();
+ --count;
+ }
+ return v;
+ }
+
+ int GetNextBit ()
+ {
+ if (m_bits_count-- <= 0)
+ {
+ m_bits = LittleEndian.ToInt32 (m_input, m_bits_src);
+ m_bits_src += 4;
+ m_bits_count = 31;
+ }
+ else
+ {
+ m_bits >>= 1;
+ }
+ return m_bits & 1;
+ }
+ }
+}
diff --git a/supported.html b/supported.html
index d92c451d..a841c50e 100644
--- a/supported.html
+++ b/supported.html
@@ -99,10 +99,13 @@ Okaa-san ga Ippai!
| *.pak | HyPack | Yes | Kogado | Symphonic Rain |
| *+*.lst | - | No | Nexton LikeC |
Chikan Ou ~Inkoku no Souzousha~
+Daisaimin Rankou Gakuen
Injoku Shinryuu Club
Moon.
Ryoujoku Famiresu Choukyou Menu
Ryoujoku Idol Mesu Dorei
+Sei Dorei Gakuen
+Seidorei Onna Kyoushi
Sentoreido Gakuen
Yakuchu!
|
@@ -735,11 +738,13 @@ Izumo 3
| *.pbx | Pandora.box | No | Terios |
Ikinari Happy Bell
|
-| *.pk | - | No | BANANA Shu-Shu |
+ |
*.pk *.dat | - | No | BANANA Shu-Shu Yellow Pig |
Tama Tama ~Tonari no Kanojo...
Tama Tama Christmas Box
+Otto no Mae de Okasarete...
|
| *.mag | - | No |
+| *.gec | - | No |
| *.arc | - | No | AI6WIN |
Gakuen Saimin Reido
|