(count);
+ for (int i = 0; i < count; ++i)
+ {
+ int name_length = LittleEndian.ToUInt16 (index, current_filename);
+ if (current_filename+2+name_length > index.Length)
+ return null;
+ uint size = LittleEndian.ToUInt32 (index, current_index+0x18);
+ if (size != 0)
+ {
+ string name = Encodings.cp932.GetString (index, current_filename+2, name_length);
+ var entry = new PackedEntry
+ {
+ Name = name,
+ Type = FormatCatalog.Instance.GetTypeFromName (name),
+ Offset = current_offset,
+ Size = size,
+ UnpackedSize = LittleEndian.ToUInt32 (index, current_index+0x10),
+ };
+ if (!entry.CheckPlacement (file.MaxOffset))
+ return null;
+ entry.IsPacked = entry.Size != entry.UnpackedSize;
+ current_offset += entry.Size;
+ dir.Add (entry);
+ }
+ current_index += 0x20;
+ current_filename += 2 + name_length;
+ }
+ return new ArcFile (file, this, dir);
+ }
+
+ public override Stream OpenEntry (ArcFile arc, Entry entry)
+ {
+ if (0 == entry.Size)
+ return Stream.Null;
+ var input = arc.File.CreateStream (entry.Offset, entry.Size);
+ var pentry = entry as PackedEntry;
+ if (null == pentry || !pentry.IsPacked)
+ return input;
+ if (!arc.File.View.AsciiEqual (entry.Offset, "GCE"))
+ {
+ Trace.WriteLine ("Packed entry is not GCE", entry.Name);
+ return input;
+ }
+ using (input)
+ using (var reader = new GceReader (input, (int)pentry.UnpackedSize))
+ {
+ return new MemoryStream (reader.Data);
+ }
+ }
+ }
+
+ internal class GceReader : IDisposable
+ {
+ BinaryReader m_input;
+ int m_unpacked_size;
+ byte[] m_output = null;
+ int m_dst;
+
+ public byte[] Data
+ {
+ get
+ {
+ if (null == m_output)
+ {
+ m_output = new byte[m_unpacked_size];
+ Unpack();
+ }
+ return m_output;
+ }
+ }
+
+ public GceReader (Stream input, int unpacked_size)
+ {
+ m_input = new ArcView.Reader (input);
+ m_unpacked_size = unpacked_size;
+ }
+
+ private void Unpack ()
+ {
+ m_dst = 0;
+ byte[] id = new byte[4];
+ while (m_input.BaseStream.Position < m_input.BaseStream.Length)
+ {
+ if (4 != m_input.Read (id, 0, 4))
+ break;
+ int segment_length = m_input.ReadInt32();
+ if (Binary.AsciiEqual (id, "GCE1"))
+ {
+ m_input.ReadInt32();
+ int data_length = m_input.ReadInt32();
+
+ m_input.ReadInt32();
+ int cmd_len = m_input.ReadInt32();
+ long cmd_pos = m_input.BaseStream.Position + data_length;
+ ReadControlStream (cmd_pos, cmd_len);
+
+ int next = m_dst + segment_length;
+ UnpackGce1Segment (data_length, segment_length);
+ m_dst = next;
+ m_input.BaseStream.Position = cmd_pos + cmd_len;
+ }
+ else if (Binary.AsciiEqual (id, "GCE0"))
+ {
+ if (segment_length != m_input.Read (m_output, m_dst, segment_length))
+ throw new EndOfStreamException();
+ m_dst += segment_length;
+ }
+ else
+ {
+ throw new InvalidFormatException ("Unknown compression type in GCE stream");
+ }
+ }
+ }
+
+ int[] m_frame = new int[0x10000];
+
+ void UnpackGce1Segment (int data_len, int segment_length)
+ {
+ for (int i = 0; i < m_frame.Length; ++i)
+ m_frame[i] = 0;
+ int frame_pos = 0;
+
+ int data_pos = 0;
+ int dst_end = m_dst + segment_length;
+ while (data_pos < data_len && m_dst < dst_end)
+ {
+ int n = GetLength();
+ while (n --> 0)
+ {
+ m_frame[frame_pos] = m_dst;
+ byte b = m_input.ReadByte();
+ data_pos++;
+ frame_pos = ((frame_pos << 8) | b) & 0xFFFF;
+ m_output[m_dst++] = b;
+ }
+ if (m_dst >= dst_end)
+ break;
+ n = GetLength() + 1;
+ int src = m_frame[frame_pos];
+ while (n --> 0)
+ {
+ m_frame[frame_pos] = m_dst;
+ frame_pos = ((frame_pos << 8) | m_output[src]) & 0xFFFF;
+ m_output[m_dst++] = m_output[src++];
+ }
+ }
+ }
+
+ int GetLength ()
+ {
+ int v = 0;
+ if (0 == GetBit())
+ {
+ int digits = 0;
+ while (0 == GetBit())
+ ++digits;
+ v = 1 << digits;
+ while (digits --> 0)
+ v |= GetBit() << digits;
+ }
+ return v;
+ }
+
+ byte[] m_control;
+ int m_control_pos;
+ int m_control_len;
+ int m_bit_pos;
+
+ void ReadControlStream (long pos, int length)
+ {
+ var data_pos = m_input.BaseStream.Position;
+ if (null == m_control || m_control.Length < length)
+ m_control = new byte[length];
+ m_input.BaseStream.Position = pos;
+ if (length != m_input.Read (m_control, 0, length))
+ throw new EndOfStreamException();
+ m_control_pos = 0;
+ m_control_len = length;
+ m_input.BaseStream.Position = data_pos;
+ m_bit_pos = 8;
+ }
+
+ int GetBit ()
+ {
+ if (0 == m_bit_pos--)
+ {
+ ++m_control_pos;
+ m_bit_pos = 7;
+ --m_control_len;
+ if (0 == m_control_len)
+ throw new EndOfStreamException();
+ }
+ return 1 & (m_control[m_control_pos] >> m_bit_pos);
+ }
+
+ #region IDisposable Members
+ bool m_disposed = false;
+ public void Dispose ()
+ {
+ if (!m_disposed)
+ {
+ if (m_input != null)
+ m_input.Dispose();
+ m_disposed = true;
+ GC.SuppressFinalize (this);
+ }
+ }
+ #endregion
+ }
+}
diff --git a/ArcFormats/ImageBGRA.cs b/ArcFormats/ImageBGRA.cs
new file mode 100644
index 00000000..a00094d8
--- /dev/null
+++ b/ArcFormats/ImageBGRA.cs
@@ -0,0 +1,75 @@
+//! \file ImageBGRA.cs
+//! \date Tue Aug 18 15:56:18 2015
+//! \brief G2 enging image format.
+//
+// Copyright (C) 2015 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.ComponentModel.Composition;
+using System.IO;
+using System.Windows.Media;
+using GameRes.Utility;
+
+namespace GameRes.Formats.G2
+{
+ [Export(typeof(ImageFormat))]
+ public class BgraFormat : ImageFormat
+ {
+ public override string Tag { get { return "BGRA"; } }
+ public override string Description { get { return "G2 engine image format"; } }
+ public override uint Signature { get { return 0x41524742; } } // 'BGRA'
+
+ public BgraFormat ()
+ {
+ Extensions = new string[] { "argb", "arg" };
+ }
+
+ public override ImageMetaData ReadMetaData (Stream stream)
+ {
+ var header = new byte[0x10];
+ if (header.Length != stream.Read (header, 0, header.Length))
+ return null;
+ uint bitmap = LittleEndian.ToUInt32 (header, 4);
+ if (0x08080808 != bitmap)
+ return null;
+ return new ImageMetaData
+ {
+ Width = LittleEndian.ToUInt32 (header, 8),
+ Height = LittleEndian.ToUInt32 (header, 12),
+ BPP = 32,
+ };
+ }
+
+ public override ImageData Read (Stream stream, ImageMetaData info)
+ {
+ stream.Seek (0x10, SeekOrigin.Current);
+ var pixels = new byte[info.Width*info.Height*4];
+ if (pixels.Length != stream.Read (pixels, 0, pixels.Length))
+ throw new EndOfStreamException();
+ return ImageData.Create (info, PixelFormats.Bgra32, null, pixels);
+ }
+
+ public override void Write (Stream file, ImageData image)
+ {
+ throw new System.NotImplementedException ("BgraFormat.Write not implemented");
+ }
+ }
+}
diff --git a/supported.html b/supported.html
index 0ba52f20..bf6d4e62 100644
--- a/supported.html
+++ b/supported.html
@@ -26,6 +26,7 @@ tr.odd td { background-color: #eee }
Anata no Osanazuma
Ecchi na Bunny-san wa Kirai?
Kana ~Imouto~
+Kohitsuji-tachi no Rakuen
Natsu no Hitoshizuku
Private Nurse
Sensei 2
@@ -92,7 +93,10 @@ Sweet Pool
Zoku Satsuriku no Django
| *.npa | - | Yes | Nitro+ | Steins;Gate |
-| *.pak | \003\000\000\000 | No | Nitro+ | Hanachirasu |
+| *.pak | \002\000\000\000 \003\000\000\000 | No | Nitro+ |
+Hanachirasu
+Jingai Makyou
+ |
*.nsa *.sar | - | Yes | NScripter |
Binary Pot
Tsukihime
@@ -289,8 +293,13 @@ Jokei Kazoku ~Inbou~
|
| *.gcc | G24n G24m R24n R24m | No |
| *.arc | - | No | Tumugi | Kimi no Omoi, Sono Negai |
| *.iks | NPSR | No | X[iks] | Shikkan ~Hazukashimerareta Karada, Oreta Kokoro~ |
-| *.wbp | ARCFORM3 WBUG | No | Wild Bug | Yuukyou Gangu 2 |
-| *.wbm | WPX | No |
+| *.wbp | ARCFORM3 WBUG | No | Wild Bug |
+Happy Planning
+Yuukyou Gangu 2
+ |
+| *.wbm | WPX\x1ABMP | No |
+| *.wpn | WBD\x1AWAV | No |
+| *.wwa | WPX\x1AWAV | No |
| *.mrg | MRG | No | F&C | Konata yori Kanata made |
| *.mcg | MCG 2.00 | No |
| *.acd | ACD 1.00 | No |
@@ -332,6 +341,10 @@ Kikouyoku Senki Gin no Toki no Corona
SuGirly Wish
| *.ykg | YKG000 | No |
+| *.pak | GCEX | No | G2 |
+Majiresu!! ~Omatase Little Wing~
+ |
+*.arg *.argb | BGRA | No |
Non-encrypted only