diff --git a/ArcFormats/Cyberworks/ArcDAT.cs b/ArcFormats/Cyberworks/ArcDAT.cs index 26b8ea88..71deb93f 100644 --- a/ArcFormats/Cyberworks/ArcDAT.cs +++ b/ArcFormats/Cyberworks/ArcDAT.cs @@ -174,6 +174,8 @@ namespace GameRes.Formats.Cyberworks Extensions = new string[] { "dat", "04", "05", "06", "app" }; } + public bool BlendOverlayImages = true; + static readonly ArchiveNameParser[] s_name_parsers = { new ArcNameParser(), new DatNameParser(), new InKyouParser() }; @@ -256,6 +258,7 @@ namespace GameRes.Formats.Cyberworks var pent = entry as PackedEntry; if (null != pent && pent.IsPacked) { + input = new BufferedStream (input); input = new LzssStream (input); } return input; @@ -269,7 +272,10 @@ namespace GameRes.Formats.Cyberworks var input = arc.OpenBinaryEntry (entry); try { - return DecryptImage (input, barc.Scheme); + var reader = DecryptImage (input, barc.Scheme); + if (BlendOverlayImages && reader is AImageReader) + reader = BlendAImage (barc, entry, reader as AImageReader); + return reader; } catch { @@ -301,6 +307,43 @@ namespace GameRes.Formats.Cyberworks return new ImageFormatDecoder (input); } + IImageDecoder BlendAImage (BellArchive arc, Entry entry, AImageReader overlay) + { + var header = overlay.ReadHeader(); + if (header[0] != 1) + return overlay; + var scheme = arc.Scheme; + var dir = (List)arc.Dir; + int i = dir.IndexOf (entry); + while (--i >= 0 && "image" == dir[i].Type) + { + using (var input = OpenEntry (arc, dir[i])) + { + int type = input.ReadByte(); + if (type != 'a') + break; + int id = input.ReadByte(); + if (id != scheme.Value2) + break; + using (var bin = new BinaryStream (input, dir[i].Name)) + using (var base_image = new AImageReader (bin, scheme)) + { + var base_header = base_image.ReadHeader(); + if (1 == base_header[0]) + continue; + // check if image width/height are the same + if (base_header[3] == header[3] && base_header[4] == header[4]) + { + base_image.Unpack(); + overlay.Baseline = base_image.Data; + } + break; + } + } + } + return overlay; + } + internal AImageScheme QueryScheme (string arc_name) { var title = FormatCatalog.Instance.LookupGame (arc_name); @@ -579,9 +622,8 @@ namespace GameRes.Formats.Cyberworks var entry = ReadEntryInfo(); if (ReadEntryType (entry, entry_size)) { - if (!entry.CheckPlacement (MaxOffset)) - return false; - m_dir.Add (entry); + if (entry.CheckPlacement (MaxOffset)) + m_dir.Add (entry); } m_index.Position = next_pos; } @@ -668,6 +710,8 @@ namespace GameRes.Formats.Cyberworks protected override bool ReadEntryType (Entry entry, int entry_size) { + if (entry_size > 0x11) + throw new InvalidFormatException(); char type = (char)m_index.ReadByte(); if (type > 0x20 && type < 0x7F) { diff --git a/ArcFormats/Cyberworks/ImageTINK.cs b/ArcFormats/Cyberworks/ImageTINK.cs index 5993c6c2..a876d691 100644 --- a/ArcFormats/Cyberworks/ImageTINK.cs +++ b/ArcFormats/Cyberworks/ImageTINK.cs @@ -51,10 +51,12 @@ namespace GameRes.Formats.Cyberworks byte[] m_output; AImageScheme m_scheme; ImageData m_image; + int[] m_header; public Stream Source { get { m_input.Position = 0; return m_input.AsStream; } } public ImageFormat SourceFormat { get { return null; } } public ImageMetaData Info { get { return m_info; } } + public byte[] Baseline { get; set; } public ImageData Image { @@ -81,17 +83,25 @@ namespace GameRes.Formats.Cyberworks m_scheme = scheme; } - public void Unpack () + internal int[] ReadHeader () { + if (m_header != null) + return m_header; int header_length = Math.Max (8, m_scheme.HeaderOrder.Length); - var header = new int[header_length]; + m_header = new int[header_length]; for (int i = 0; i < m_scheme.HeaderOrder.Length; ++i) { int b = GetInt(); - header[m_scheme.HeaderOrder[i]] = b; + m_header[m_scheme.HeaderOrder[i]] = b; } - Info.Width = (uint)header[4]; - Info.Height = (uint)header[3]; + Info.Width = (uint)m_header[4]; + Info.Height = (uint)m_header[3]; + return m_header; + } + + public void Unpack () + { + var header = ReadHeader(); if (0 == Info.Width || Info.Width >= 0x8000 || 0 == Info.Height || Info.Height >= 0x8000) throw new InvalidFormatException(); int unpacked_size = header[5]; @@ -160,22 +170,32 @@ namespace GameRes.Formats.Cyberworks if (alpha_map.Length != alpha_size) throw new InvalidFormatException(); - Info.BPP = 32; int plane_size = (int)Info.Width * (int)Info.Height; - m_output = new byte[plane_size * 4]; + if (Baseline != null) + { + Info.BPP = 24; + m_output = Baseline; + } + else + { + Info.BPP = 32; + m_output = new byte[plane_size * 4]; + } + int pixel_size = Info.BPP / 8; int bit = 1; int bit_src = 0; int dst = 0; for (int i = 0; i < plane_size; ++i) { + byte alpha = 0; if ((bit & alpha_map[bit_src]) != 0) { m_input.Read (m_output, dst, 3); - m_output[dst+3] = 0xFF; + alpha = 0xFF; } - else - m_output[dst+3] = 0; - dst += 4; + if (4 == pixel_size) + m_output[dst+3] = alpha; + dst += pixel_size; if (0x80 == bit) { ++bit_src;