diff --git a/ArcFormats/ArcFormats.csproj b/ArcFormats/ArcFormats.csproj
index f8e37d86..ad15eb57 100644
--- a/ArcFormats/ArcFormats.csproj
+++ b/ArcFormats/ArcFormats.csproj
@@ -131,7 +131,9 @@
+
+
WidgetDXA.xaml
@@ -142,8 +144,10 @@
+
+
diff --git a/ArcFormats/DigitalWorks/ArcPACsingle.cs b/ArcFormats/DigitalWorks/ArcPACsingle.cs
new file mode 100644
index 00000000..310823c1
--- /dev/null
+++ b/ArcFormats/DigitalWorks/ArcPACsingle.cs
@@ -0,0 +1,88 @@
+//! \file ArcPACPS2.cs
+//! \date 2018 Sep 18
+//! \brief Digital Works PS2 resource archive.
+//
+// Copyright (C) 2018 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.Collections.Generic;
+using System.ComponentModel.Composition;
+using System.IO;
+using GameRes.Compression;
+
+namespace GameRes.Formats.DigitalWorks
+{
+ [Export(typeof(ArchiveFormat))]
+ public class PacSingleOpener : ArchiveFormat
+ {
+ public override string Tag { get { return "PAC/LZS-TIM2"; } }
+ public override string Description { get { return "LZS-TIM2 Image archive"; } }
+ public override uint Signature { get { return 0x535A4C; } } // 'LZS'
+ public override bool IsHierarchic { get { return false; } }
+ public override bool CanWrite { get { return false; } }
+
+ /**
+ Target games:
+ Cafe Little Wish SLPM-65294
+ F Fanatic SLPM-65296
+ */
+
+ public override ArcFile TryOpen (ArcView file)
+ {
+ if (!file.View.AsciiEqual(9, "TIM2"))
+ return null;
+ var dir = new List (1);
+ var entry = FormatCatalog.Instance.Create (file.Name);
+ entry.Offset = 0L;
+ entry.Size = (uint)file.MaxOffset;
+ if (!entry.CheckPlacement (file.MaxOffset))
+ return null;
+ dir.Add (entry);
+
+ return new ArcFile (file, this, dir);
+ }
+
+ public override Stream OpenEntry (ArcFile arc, Entry entry)
+ {
+ var pent = entry as PackedEntry;
+ if (null == pent)
+ return base.OpenEntry (arc, entry);
+ if (!pent.IsPacked)
+ {
+ if (!arc.File.View.AsciiEqual (entry.Offset, "LZS\0"))
+ return base.OpenEntry (arc, entry);
+ pent.IsPacked = true;
+ pent.UnpackedSize = arc.File.View.ReadUInt32 (entry.Offset+4);
+ }
+ var input = arc.File.CreateStream (entry.Offset+8, entry.Size-8);
+ bool embedded_lzs = (input.Signature & ~0xF0u) == 0x535A4C0F; // 'LZS'
+ var lzs = new LzssStream (input);
+ if (embedded_lzs)
+ {
+ var header = new byte[8];
+ lzs.Read (header, 0, 8);
+ pent.UnpackedSize = header.ToUInt32 (4);
+ lzs = new LzssStream (lzs);
+ }
+ return lzs;
+ }
+ }
+}
diff --git a/ArcFormats/DigitalWorks/ImageTM2.cs b/ArcFormats/DigitalWorks/ImageTM2.cs
index 2c3a6afc..b5ce73f4 100644
--- a/ArcFormats/DigitalWorks/ImageTM2.cs
+++ b/ArcFormats/DigitalWorks/ImageTM2.cs
@@ -23,6 +23,7 @@
// IN THE SOFTWARE.
//
+using GameRes.Formats.Strings;
using System;
using System.ComponentModel.Composition;
using System.IO;
@@ -36,6 +37,7 @@ namespace GameRes.Formats.DigitalWorks
public int PaletteSize;
public int HeaderSize;
public int Colors;
+ public byte Alpha;
}
[Export(typeof(ImageFormat))]
@@ -48,8 +50,16 @@ namespace GameRes.Formats.DigitalWorks
public Tim2Format ()
{
Extensions = new string[] { "tm2", "ext" };
+ Settings = new[] { AlphaFormat };
}
+ FixedSetSetting AlphaFormat = new FixedSetSetting(Properties.Settings.Default)
+ {
+ Name = "TIM2AlphaFormat",
+ Text = arcStrings.Tim2AlphaFormat,
+ ValuesSet = new[] { "No Alpha", "RGBX", "RGBA" },
+ };
+
public override ImageMetaData ReadMetaData (IBinaryStream file)
{
var header = file.ReadHeader (0x40);
@@ -59,9 +69,18 @@ namespace GameRes.Formats.DigitalWorks
case 1: bpp = 16; break;
case 2: bpp = 24; break;
case 3: bpp = 32; break;
+ case 4: bpp = 4; break; //16color
case 5: bpp = 8; break;
default: return null;
}
+ byte alpha;
+ switch (AlphaFormat.Get())
+ {
+ case "No Alpha": alpha = 0; break;
+ case "RGBX": alpha = 7; break;
+ case "RGBA":
+ default: alpha = 8; break;
+ }
return new Tim2MetaData {
Width = header.ToUInt16 (0x24),
Height = header.ToUInt16 (0x26),
@@ -69,6 +88,7 @@ namespace GameRes.Formats.DigitalWorks
PaletteSize = header.ToInt32 (0x14),
HeaderSize = header.ToUInt16 (0x1C),
Colors = header.ToUInt16 (0x1E),
+ Alpha = alpha, //header.ToUInt16(0x30) == 0?// not so sure, there will be omissions
};
}
@@ -99,39 +119,69 @@ namespace GameRes.Formats.DigitalWorks
m_info = info;
switch (info.BPP)
{
- case 8: Format = PixelFormats.Indexed8; break;
- case 16: Format = PixelFormats.Bgr555; break;
- case 24: Format = PixelFormats.Bgr24; break;
- case 32: Format = PixelFormats.Bgra32; break;
+ case 4: Format = PixelFormats.Indexed4; break;
+ case 8: Format = PixelFormats.Indexed8; break;
+ case 16: Format = PixelFormats.Bgr555; break;
+ case 24: Format = PixelFormats.Bgr24; break;
+ case 32: Format = PixelFormats.Bgra32; break;
}
}
public byte[] Unpack ()
{
m_input.Position = 0x10 + m_info.HeaderSize;
- int pixel_size = m_info.BPP / 8;
- int image_size = (int)m_info.Width * (int)m_info.Height * pixel_size;
+ double pixel_size = (double)m_info.BPP / 8;
+ int image_size = (int)((int)m_info.Width * (int)m_info.Height * pixel_size);
var output = m_input.ReadBytes (image_size);
if (pixel_size <= 8 && m_info.Colors > 0)
- Palette = ReadPalette (m_info.Colors);
+ Palette = ReadPalette (m_info.Colors, m_info.Alpha);
- if (pixel_size >= 3)
+ if (pixel_size == 3 || pixel_size == 4 && m_info.Alpha == 8)
{
- for (int i = 0; i < image_size; i += pixel_size)
+ for (int i = 0; i < image_size; i += (int)pixel_size)
{
byte r = output[i];
output[i] = output[i+2];
output[i+2] = r;
}
}
+ if (pixel_size == 4 && m_info.Alpha == 7)
+ {
+ for (int i = 0; i < image_size; i += 4)
+ {
+ byte r = output[i];
+ output[i] = output[i + 2];
+ output[i + 2] = r;
+ if (output[i + 3] >= byte.MaxValue / 2)
+ output[i + 3] = byte.MaxValue;
+ else
+ output[i + 3] = (byte)(output[i + 3] << 1);
+ }
+ }
+ if (pixel_size == 4 && m_info.Alpha == 0)
+ {
+ for (int i = 0; i < image_size; i += 4)
+ {
+ byte r = output[i];
+ output[i] = output[i + 2];
+ output[i + 2] = r;
+ output[i + 3] = byte.MaxValue;
+ }
+ }
return output;
}
- BitmapPalette ReadPalette (int color_num)
+ BitmapPalette ReadPalette (int color_num, byte X_A = 8)
{
- var source = ImageFormat.ReadColorMap (m_input.AsStream, color_num, PaletteFormat.RgbA);
+ var source = ImageFormat.ReadColorMap (m_input.AsStream,
+ color_num, X_A == 7 ? PaletteFormat.RgbA7 : X_A == 0 ? PaletteFormat.RgbX : PaletteFormat.RgbA);
var color_map = new Color[color_num];
+ if (color_num == 16){
+ Array.Copy(source, 0, color_map, 0, 16);
+ return new BitmapPalette(color_map);
+ }
+
int parts = color_num / 32;
const int blocks = 2;
const int rows = 2;
diff --git a/ArcFormats/DigitalWorks/ImageTM2arc.cs b/ArcFormats/DigitalWorks/ImageTM2arc.cs
new file mode 100644
index 00000000..f7be9250
--- /dev/null
+++ b/ArcFormats/DigitalWorks/ImageTM2arc.cs
@@ -0,0 +1,53 @@
+using GameRes.Compression;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.Composition;
+using System.IO;
+
+namespace GameRes.Formats.DigitalWorks
+{
+ [Export(typeof(ImageFormat))]
+ public class TM2ArkFormat : Tim2Format
+ {
+ public override string Tag { get { return "TIM2/PS2 compressed"; } }
+ public override string Description { get { return "PlayStation/2 image format with LZSS compress"; } }
+ public override uint Signature { get { return 0x535A4C; } } // 'LZS'
+ public TM2ArkFormat()
+ {
+ Extensions = new string[] { "tm2" };
+ Settings = null;
+ }
+
+ public override ImageMetaData ReadMetaData(IBinaryStream stream)
+ {
+ stream.Position = 9;
+ uint real_sign = stream.ReadUInt32();
+ //Tim2Format tm2raw = new Tim2Format();
+ if (real_sign != base.Signature)
+ {
+ return null;
+ }
+ stream.Position = 4;
+ uint unpacked_size = stream.ReadUInt32();
+ if (unpacked_size <= 0x20 || unpacked_size > 0x5000000) // ~83MB
+ return null;
+ stream.Position = 8;
+ using (var lzss = new LzssStream(stream.AsStream, LzssMode.Decompress, true))
+ using (var input = new SeekableStream(lzss))
+ using (var tm2 = new BinaryStream(input, stream.Name))
+ return base.ReadMetaData(tm2);
+ }
+ public override ImageData Read(IBinaryStream stream, ImageMetaData info)
+ {
+ stream.Position = 8;
+ using (var lzss = new LzssStream(stream.AsStream, LzssMode.Decompress, true))
+ using (var input = new SeekableStream(lzss))
+ using (var tm2 = new BinaryStream(input, stream.Name))
+ return base.Read(tm2, info);
+ }
+ public override void Write(Stream file, ImageData image)
+ {
+ throw new System.NotImplementedException("TM2ArkFormat.Write not implemented");
+ }
+ }
+}
diff --git a/ArcFormats/Kid/ArcKLZ.cs b/ArcFormats/Kid/ArcKLZ.cs
new file mode 100644
index 00000000..e073bb70
--- /dev/null
+++ b/ArcFormats/Kid/ArcKLZ.cs
@@ -0,0 +1,122 @@
+using GameRes.Utility;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.Composition;
+using System.IO;
+
+namespace GameRes.Formats.Kid
+{
+ [Export(typeof(ArchiveFormat))]
+ public class KlzOpener: ArchiveFormat
+ {
+ public override string Tag { get { return "KLZ/KID PS2"; } }
+ public override string Description { get { return "KID PS2 compressed image format with multi TIM2"; } }
+ public override uint Signature { get { return 0; } }
+ public override bool IsHierarchic { get { return false; } }
+ public override bool CanWrite { get { return false; } }
+
+ public KlzOpener()
+ {
+ Extensions = new string[] { "klz" };
+ }
+
+ public override ArcFile TryOpen(ArcView file)
+ {
+ if (!file.Name.HasExtension(".klz"))
+ return null;
+ uint unpacked_size = Binary.BigEndian(file.View.ReadUInt32(0));
+ if (unpacked_size <= 0x20 || unpacked_size > 0x5000000)
+ return null;
+
+ var backend = file.CreateStream();
+ var input = KlzFormat.LzhStreamDecode(backend);
+ var base_name = Path.GetFileNameWithoutExtension(file.Name);
+ var dir = GetEntries(input, base_name);
+ if (dir == null || dir.Count == 0)
+ {
+ return null;
+ }
+ else
+ {
+ return new KlzArchive(file, this, dir, input);
+ }
+ //throw new NotImplementedException();
+ }
+
+ public override Stream OpenEntry(ArcFile arc, Entry entry)
+ {
+ return new StreamRegion(((KlzArchive)arc).Source, entry.Offset, entry.Size, true);
+ }
+
+ internal static List GetEntries (Stream input, string base_name)
+ {
+ var entries = new List();
+ BinaryReader m_input = new ArcView.Reader(input);
+ int count = 0;
+ m_input.BaseStream.Position = 0;
+ while (m_input.BaseStream.Position < m_input.BaseStream.Length)
+ {
+ while (true)
+ {
+ try
+ {
+ uint sign = m_input.ReadUInt32();
+ m_input.ReadBytes(12);
+ if (sign == 0x324D4954) //TIM2
+ {
+ //m_input.BaseStream.Seek(-4, SeekOrigin.Current);
+ break;
+ }
+ }
+ catch (EndOfStreamException)
+ {
+ return entries;
+ }
+ }
+ long tell = m_input.BaseStream.Position - 16;
+ uint size = m_input.ReadUInt32() + 16;
+ string name = base_name + "_" + count.ToString("D2");
+ if (tell + size > m_input.BaseStream.Length)
+ {
+ size = (uint)(m_input.BaseStream.Length - tell);
+ name += "_incomplete";
+ }
+ var entry = new Entry {
+ Name = name + ".tm2",
+ Size = size,
+ Offset = tell,
+ Type = "image"
+ };
+ count++;
+ entries.Add(entry);
+ m_input.BaseStream.Position = tell + size;
+ }
+ return entries;
+ }
+ }
+
+ internal class KlzArchive : ArcFile
+ {
+ public readonly Stream Source;
+ public KlzArchive(ArcView arc, ArchiveFormat impl, ICollection dir, Stream input)
+ : base (arc, impl, dir)
+ {
+ Source = input;
+ }
+
+ #region IDisposable Members
+ bool _spc_disposed = false;
+ protected override void Dispose(bool disposing)
+ {
+ if (_spc_disposed)
+ return;
+ if (disposing)
+ {
+ Source.Dispose();
+ }
+ _spc_disposed = true;
+ base.Dispose(disposing);
+ }
+ #endregion
+ }
+}
diff --git a/ArcFormats/Kid/ImageKLZ.cs b/ArcFormats/Kid/ImageKLZ.cs
new file mode 100644
index 00000000..b8be2adb
--- /dev/null
+++ b/ArcFormats/Kid/ImageKLZ.cs
@@ -0,0 +1,313 @@
+using GameRes.Utility;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.Composition;
+using System.IO;
+using System.Linq;
+
+namespace GameRes.Formats.Kid
+{
+ [Export(typeof(ImageFormat))]
+ public class KlzFormat: DigitalWorks.Tim2Format
+ {
+ public override string Tag { get { return "KLZ/KID PS2 compressed TIM2"; } }
+ public override string Description { get { return "KID PS2 compressed TIM2 image format"; } }
+ public override uint Signature { get { return 0; } } //KLZ have no header
+ public KlzFormat()
+ {
+ Extensions = new string[] { "klz" };
+ Settings = null;
+ }
+
+ public override ImageMetaData ReadMetaData(IBinaryStream stream)
+ {
+ uint unpacked_size = Binary.BigEndian(stream.Signature);
+ if (unpacked_size <= 0x20 || unpacked_size > 0x5000000) // ~83MB
+ return null;
+ stream.Position = 0;
+ //Stream streamdec = LzsStreamDecode(stream);
+ //using (var lzss = new LzssStream(stream.AsStream, LzssMode.Decompress, true))
+ using (var input = new SeekableStream(LzhStreamDecode(stream)))
+ using (var tm2 = new BinaryStream(input, stream.Name))
+ return base.ReadMetaData(tm2);
+ }
+ public override ImageData Read(IBinaryStream stream, ImageMetaData info)
+ {
+ //stream.Position = 4;
+ //using (var lzss = new LzssStream(stream.AsStream, LzssMode.Decompress, true))
+ using (var input = new SeekableStream(LzhStreamDecode(stream)))
+ using (var tm2 = new BinaryStream(input, stream.Name))
+ return base.Read(tm2, info);
+ }
+ public override void Write(Stream file, ImageData image)
+ {
+ throw new System.NotImplementedException("KlzFormat.Write not implemented");
+ }
+
+ ///
+ /// Original lzh_decode_mips
+ ///
+ /// The following code is from punk7890/PS2-Visual-Novel-Tool under MIT license.
+ /// Source code: https://github.com/punk7890/PS2-Visual-Novel-Tool/blob/ac5602fbf13d15ce1bfaa27dc2263373cfebc0e5/src/scenes/kid.gd#L104
+ /// input stream, include header
+ ///
+ public static Stream LzhStreamDecode(IBinaryStream input) {
+ byte[] out_bytes = new byte[0x4000];
+ List f_out_bytes = new List();
+ uint output_size = Binary.BigEndian(input.ReadUInt32());
+ ushort fill_count = Binary.BigEndian(input.ReadUInt16());
+ bool at;
+ int v0, s0 = 0, s1, s3;
+ byte v1; //byte a0
+ ushort s2;
+ int OO40_sp = 0, OO42_sp = 0, OO44_sp, OO48_sp, OO50_sp = 0, OO60_sp = 0, OO70_sp = fill_count;
+ int next_read_pos = 0;
+ int count = 0;
+ int num_passes = 0;
+ byte[] decode_table = new byte[] {
+ 0x01, 0x02, 0x04, 0x08,
+ 0x10, 0x20, 0x40, 0x80,
+ // Only first 8 are used
+ 0x81, 0x75, 0x81, 0x69,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x00, 0x00
+ };
+ // out.resize(0x4000)
+ /*int temp = 0x4000;
+ while (temp > 0)
+ {
+ out_bytes.Add(0);
+ temp--;
+ }*/
+ //out_bytes = Enumerable.Repeat((byte)0, 0x4000);
+ // out.resize(0x4000) end
+ if (fill_count > 0x4000)
+ {
+ next_read_pos = 4;
+ while (OO70_sp > 0x4000)
+ {
+ int cnt = 0;
+ int copy_off = next_read_pos + 2;
+ while (cnt < 0x4000)
+ {
+ input.Position = copy_off;
+ f_out_bytes.Add(input.ReadUInt8());
+ cnt++;
+ copy_off++;
+ }
+ count += 0x4000;
+ next_read_pos += cnt + 2;
+ num_passes++;
+ input.Position = next_read_pos;
+ OO70_sp = Binary.BigEndian(input.ReadUInt16());
+ if (count >= output_size || next_read_pos >= input.Length)
+ {
+ Stream stream = new MemoryStream(f_out_bytes.ToArray());
+ return stream;
+ }
+ OO60_sp = next_read_pos + 2;
+ }
+ }
+ else
+ {
+ OO60_sp = 6;
+ }
+
+ OO44_sp = OO60_sp;
+ /*v0 = OO60_sp + 1;
+ OO48_sp = v0;*/
+ OO48_sp = OO60_sp + 1;
+ while (true){
+ input.Position = OO44_sp;
+ //input.Seek(OO44_sp, SeekOrigin.Begin);
+ /*v0 = input.ReadUInt8();
+ a0 = v0 & 0xFF;*/
+ //a0 = input.ReadUInt8();
+ /*v0 = OO40_sp;
+ v1 = v0 & 0xFF;*/
+ v0 = decode_table[OO40_sp & 0xFF] & input.ReadUInt8();
+ //v0 &= a0;
+ // #001BA8AC
+ if (v0 == 0)
+ {
+ input.Position = OO48_sp;
+ //input.Seek(OO48_sp, SeekOrigin.Begin);
+ v1 = input.ReadUInt8();
+ v0 = OO50_sp + s0;
+ /*out_bytes.RemoveAt(v0);
+ out_bytes.Insert(v0, v1);*/
+ out_bytes[v0] = v1;
+ OO48_sp++;
+ OO42_sp++;
+ s0++;
+ }
+ else if (v0 != 0) {
+ // # 001BA8F0
+ OO42_sp += 2;
+ input.Position = OO48_sp;
+ // input.Seek(OO48_sp, SeekOrigin.Begin);
+ /*v0 = input.ReadUInt8() & 0xFF;
+ v1 = v0 << 8;
+ v0 = input.ReadUInt8() & 0xFF;
+ v0 = v1 | v0;
+ v0 &= 0xFFFF;*/
+ s2 = Binary.BigEndian(input.ReadUInt16());
+ /*s2 = v0 & 0xFFFF;
+ v0 = s2 & 0xFFFF;*/
+ //v0 = s2;
+ //v0 = (s2 & 0x1F);
+ //v0 += 2;
+ //v0 &= 0xFFFF;
+ /*s3 = v0 & 0xFFFF;
+ v0 = s2 & 0xFFFF;*/
+ s3 = (s2 & 0x1F) + 2;
+ //v0 = s2;
+ //v0 >>= 5;
+ /*v0 &= 0xFFFF;
+ s1 = v0 & 0xFFFF;
+ v0 = s1 & 0xFFFF;*/
+ v0 = s0 - (s2 >> 5) - 1;
+ //v0 -= 1;
+ //v0 &= 0xFFFF;
+ s1 = v0 & 0xFFFF;
+ OO48_sp += 1;
+ v0 = 1;
+ while (v0 != 0)
+ {
+ at = s0 < 0x0800;
+ // # 001BA96C
+ if (at)
+ {
+ v0 = s1 & 0xFFFF;
+ at = s0 < v0;
+ if (at)
+ {
+ v1 = out_bytes[OO50_sp];
+ v0 = OO50_sp + s0;
+ /*out_bytes.RemoveAt(v0);
+ out_bytes.Insert(v0, v1);*/
+ out_bytes[v0] = v1;
+ s0 += 1;
+ /*v0 = s1 + 1;
+ s1 = v0 & 0xFFFF;*/
+ s1 = (s1 + 1) & 0xFFFF;
+ // # 001BA9D8
+ /*v1 = s3;
+ v0 = v1 - 1;
+ s3 = v0 & 0xFFFF;
+ v0 = v1 & 0xFFFF;*/
+ v0 = s3 & 0xFFFF;
+ s3 = (s3 - 1) & 0xFFFF;
+ continue;
+ }
+ }
+ // # 001BA9B0
+ /*v1 = s1 & 0xFFFF;
+ v0 = OO50_sp;
+ v0 += v1;*/
+ //v0 = OO50_sp + s1 & 0xFFFF;
+ //v1 = out_bytes[v0];
+ v1 = out_bytes[OO50_sp + s1 & 0xFFFF];
+ v0 = OO50_sp;
+ v0 += s0;
+ /*out_bytes.RemoveAt(v0);
+ out_bytes.Insert(v0, v1);*/
+ out_bytes[v0] = v1;
+ s0 += 1;
+ //v0 = s1 + 1;
+ s1 = (s1 + 1) & 0xFFFF;
+ // # 001BA9D8
+ /*v1 = s3;
+ v0 = v1 - 1;
+ s3 = v0 & 0xFFFF;
+ v0 = v1 & 0xFFFF;*/
+ v0 = s3 & 0xFFFF;
+ s3 = s3 - 1 & 0xFFFF;
+ }
+ OO48_sp += 1;
+ }
+ // # 001BAA00
+ OO40_sp += 1;
+ //v1 = Convert.ToByte(OO40_sp & 0xFF);
+ //v0 = 8;
+ if ((OO40_sp & 0xFF) == 8)
+ {
+ OO40_sp = 0;
+ OO44_sp = OO48_sp;
+ OO48_sp += 1;
+ OO42_sp += 1;
+ }
+ /*v0 = OO42_sp;
+ v1 = v0 & 0xFFFF;
+ v0 = OO70_sp;
+ v0 -= 1;*/
+ //v0 = v1 < v0 ? 1 : 0;
+ v0 = OO42_sp < OO70_sp - 1 ? 1 : 0;
+ if (v0 == 0)
+ {
+ count += s0;
+ if (count >= output_size || next_read_pos >= input.Length)
+ {
+ f_out_bytes.AddRange(out_bytes);
+ Stream stream = new MemoryStream(f_out_bytes.ToArray());
+ return stream;
+ }
+ num_passes += 1;
+ if (num_passes == 1)
+ {
+ next_read_pos += OO70_sp + 6;
+ }
+ else
+ {
+ next_read_pos += OO70_sp + 2;
+ }
+
+ f_out_bytes.AddRange(out_bytes);
+ // # out.fill(0);
+ input.Position = next_read_pos;
+ OO70_sp = Binary.BigEndian(input.ReadUInt16());
+ if (OO70_sp > 0x4000)
+ {
+ while (OO70_sp > 0x4000)
+ {
+ int cnt = 0;
+ int copy_off = next_read_pos + 2;
+ while (cnt < 0x4000)
+ {
+ input.Position = copy_off;
+ f_out_bytes.Add(input.ReadUInt8());
+ cnt += 1;
+ copy_off += 1;
+ }
+ count += 0x4000;
+ next_read_pos += cnt + 2;
+ input.Position = next_read_pos;
+ OO70_sp = Binary.BigEndian(input.ReadUInt16());
+ if (count >= output_size || next_read_pos >= input.Length)
+ {
+ Stream stream = new MemoryStream(f_out_bytes.ToArray());
+ return stream;
+ }
+ }
+ }
+ s0 = 0;
+ //s1 = 0;
+ OO50_sp = 0;
+ OO42_sp = 0;
+ OO48_sp = next_read_pos + 2;
+ if (OO48_sp > input.Length) {
+ Stream stream = new MemoryStream(f_out_bytes.ToArray());
+ return stream;
+ }
+ OO40_sp = 0;
+ OO60_sp = OO48_sp;
+ OO44_sp = OO60_sp;
+ v0 = OO60_sp + 1;
+ OO48_sp = v0;
+ }
+ }
+ //Stream stream_out = new MemoryStream(f_out_bytes.ToArray());
+ //return stream_out;
+ }
+ }
+}
diff --git a/ArcFormats/MAGES/ArcARC20.cs b/ArcFormats/MAGES/ArcARC20.cs
index a8c3f1cd..9c7a16c5 100644
--- a/ArcFormats/MAGES/ArcARC20.cs
+++ b/ArcFormats/MAGES/ArcARC20.cs
@@ -11,7 +11,7 @@ namespace GameRes.Formats.MAGES
public override string Tag { get { return "ARC/Princess Soft ARC20"; } }
public override string Description { get { return "Princess Soft PS2 resource archive"; } }
public override uint Signature { get { return 0x20435241; } } // 'ARC\x20'
- public override bool IsHierarchic { get { return false; } }
+ public override bool IsHierarchic { get { return true; } }
public override bool CanWrite { get { return false; } }
public override ArcFile TryOpen(ArcView file)
diff --git a/ArcFormats/Properties/Settings.Designer.cs b/ArcFormats/Properties/Settings.Designer.cs
index f22c61a8..4bad779b 100644
--- a/ArcFormats/Properties/Settings.Designer.cs
+++ b/ArcFormats/Properties/Settings.Designer.cs
@@ -837,5 +837,17 @@ namespace GameRes.Formats.Properties {
this["NexasEncodingCP"] = value;
}
}
+
+ [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("RGBA")]
+ public string TIM2AlphaFormat {
+ get {
+ return ((string)(this["TIM2AlphaFormat"]));
+ }
+ set {
+ this["TIM2AlphaFormat"] = value;
+ }
+ }
}
}
diff --git a/ArcFormats/Properties/Settings.settings b/ArcFormats/Properties/Settings.settings
index a6aa5543..50457412 100644
--- a/ArcFormats/Properties/Settings.settings
+++ b/ArcFormats/Properties/Settings.settings
@@ -206,5 +206,8 @@
932
+
+ RGBA
+
\ No newline at end of file
diff --git a/ArcFormats/Strings/arcStrings.Designer.cs b/ArcFormats/Strings/arcStrings.Designer.cs
index c42b4340..accb3959 100644
--- a/ArcFormats/Strings/arcStrings.Designer.cs
+++ b/ArcFormats/Strings/arcStrings.Designer.cs
@@ -752,6 +752,16 @@ namespace GameRes.Formats.Strings {
}
}
+ ///
+ /// Looks up a localized string similar to Choose Tim2 image alpha format.
+ /// It can't be read correctly from the file.
+ ///
+ public static string Tim2AlphaFormat {
+ get {
+ return ResourceManager.GetString("Tim2AlphaFormat", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Hex number.
///
diff --git a/ArcFormats/Strings/arcStrings.ja-JP.resx b/ArcFormats/Strings/arcStrings.ja-JP.resx
index 09cb1f5f..ea90ba37 100644
--- a/ArcFormats/Strings/arcStrings.ja-JP.resx
+++ b/ArcFormats/Strings/arcStrings.ja-JP.resx
@@ -501,4 +501,8 @@ Choose encryption scheme or enter a passphrase.
Default audio sampling rate
+
+ Tim2画像のAlpha形式を選択してください。
+ファイルから正しく読み取ることができません。
+
\ No newline at end of file
diff --git a/ArcFormats/Strings/arcStrings.resx b/ArcFormats/Strings/arcStrings.resx
index 435a145e..8543086c 100644
--- a/ArcFormats/Strings/arcStrings.resx
+++ b/ArcFormats/Strings/arcStrings.resx
@@ -401,4 +401,8 @@ Choose encryption scheme or enter a passphrase.
Default audio sampling rate
+
+ Choose Tim2 image alpha format.
+It can't be read correctly from the file.
+
\ No newline at end of file
diff --git a/ArcFormats/Strings/arcStrings.zh-Hans.resx b/ArcFormats/Strings/arcStrings.zh-Hans.resx
index 97a8a221..056eb3ec 100644
--- a/ArcFormats/Strings/arcStrings.zh-Hans.resx
+++ b/ArcFormats/Strings/arcStrings.zh-Hans.resx
@@ -399,4 +399,8 @@
默认音频采样率
+
+ 选择Tim2图片透明度格式。
+这无法从文件中正确获取。
+
\ No newline at end of file
diff --git a/ArcFormats/app.config b/ArcFormats/app.config
index eb7f9ea8..ef1cc161 100644
--- a/ArcFormats/app.config
+++ b/ArcFormats/app.config
@@ -208,6 +208,9 @@
932
+
+ RGBA
+
diff --git a/GameRes/Image.cs b/GameRes/Image.cs
index f52ce64c..da5e4105 100644
--- a/GameRes/Image.cs
+++ b/GameRes/Image.cs
@@ -71,6 +71,8 @@ namespace GameRes
BgrX = 6,
RgbA = 9,
BgrA = 10,
+ RgbA7 = 55,
+ BgrA7 = 66,
}
public class ImageData
@@ -124,7 +126,8 @@ namespace GameRes
public static ImageData Create (ImageMetaData info, PixelFormat format, BitmapPalette palette,
Array pixel_data)
{
- return Create (info, format, palette, pixel_data, (int)info.Width*((format.BitsPerPixel+7)/8));
+ return Create (info, format, palette, pixel_data,
+ format.BitsPerPixel == 4 ? (int)info.Width*format.BitsPerPixel/8 : (int)info.Width*((format.BitsPerPixel+7)/8));
}
public static ImageData CreateFlipped (ImageMetaData info, PixelFormat format, BitmapPalette palette,
@@ -215,12 +218,16 @@ namespace GameRes
Func get_color;
if (PaletteFormat.Bgr == format || PaletteFormat.BgrX == format)
get_color = x => Color.FromRgb (palette_data[x+2], palette_data[x+1], palette_data[x]);
+ else if (PaletteFormat.BgrA7 == format)
+ get_color = x => Color.FromArgb(palette_data[x+3] >= byte.MaxValue / 2 ? byte.MaxValue : (byte)(palette_data[x+3] << 1), palette_data[x+2], palette_data[x+1], palette_data[x]);
else if (PaletteFormat.BgrA == format)
get_color = x => Color.FromArgb (palette_data[x+3], palette_data[x+2], palette_data[x+1], palette_data[x]);
else if (PaletteFormat.RgbA == format)
get_color = x => Color.FromArgb (palette_data[x+3], palette_data[x], palette_data[x+1], palette_data[x+2]);
+ else if (PaletteFormat.RgbA7 == format)
+ get_color = x => Color.FromArgb (palette_data[x+3] >= byte.MaxValue / 2 ? byte.MaxValue : (byte)(palette_data[x+3] << 1), palette_data[x], palette_data[x+1], palette_data[x+2]);
else
- get_color = x => Color.FromRgb (palette_data[x], palette_data[x+1], palette_data[x+2]);
+ get_color = x => Color.FromRgb (palette_data[x], palette_data[x+1], palette_data[x+2]);
for (int i = 0; i < colors; ++i)
{