(arc_list.Count+1);
+ bounds.Add (max_offset);
+ foreach (var arc_entry in arc_list)
+ {
+ var arc_file = VFS.OpenView (arc_entry);
+ arc_set.Add (arc_file);
+ max_offset += arc_file.MaxOffset;
+ bounds.Add (max_offset);
+ }
+ foreach (EpkEntry entry in dir)
+ {
+ if (!entry.CheckPlacement (max_offset))
+ return null;
+ entry.ArcNumber = bounds.FindIndex (x => x > entry.Offset);
+ if (entry.ArcNumber > 0)
+ entry.Offset -= bounds[entry.ArcNumber-1];
+ }
+ var arc = new EpkArchive (file, this, dir, arc_set);
+ arc_set = null;
+ return arc;
+ }
+ finally
+ {
+ if (arc_set != null)
+ {
+ foreach (var arc in arc_set)
+ arc.Dispose();
+ }
+ }
+ }
+
+ public override Stream OpenEntry (ArcFile arc, Entry entry)
+ {
+ var earc = arc as EpkArchive;
+ var eent = entry as EpkEntry;
+ if (null == earc || null == eent)
+ return base.OpenEntry (arc, entry);
+ long entry_offset = entry.Offset;
+ ArcView file = arc.File;
+ if (eent.ArcNumber > 0)
+ file = earc.Parts[eent.ArcNumber-1];
+ if (entry_offset + entry.Size <= file.MaxOffset)
+ return file.CreateStream (entry_offset, entry.Size);
+ uint first_part_size = (uint)(file.MaxOffset - entry_offset);
+ var begin = file.CreateStream (entry_offset, first_part_size);
+ var end = earc.Parts[eent.ArcNumber].CreateStream (0, entry.Size - first_part_size);
+ return new ConcatStream (begin, end);
+ }
+ }
+
+ ///
+ /// Concatenation of the two input Streams.
+ ///
+ public class ConcatStream : InputProxyStream
+ {
+ Stream m_second;
+ long m_position;
+ Stream m_active;
+
+ public ConcatStream (Stream first, Stream second) : base (first)
+ {
+ m_second = second;
+ m_position = 0;
+ m_active = first;
+ }
+
+ internal Stream First { get { return BaseStream; } }
+ internal Stream Second { get { return m_second; } }
+
+ public override bool CanSeek { get { return First.CanSeek && Second.CanSeek; } }
+ public override long Length { get { return First.Length + Second.Length; } }
+ public override long Position
+ {
+ get { return m_position; }
+ set { m_position = value; }
+ }
+
+ public override int Read (byte[] buffer, int offset, int count)
+ {
+ if (First.CanSeek)
+ {
+ if (m_position >= First.Length)
+ {
+ m_active = Second;
+ m_active.Position = m_position - First.Length;
+ }
+ else
+ {
+ m_active = First;
+ m_active.Position = m_position;
+ }
+ }
+ int total_read = 0;
+ while (count > 0)
+ {
+ int read = m_active.Read (buffer, offset, count);
+ if (0 == read)
+ break;
+ total_read += read;
+ m_position += read;
+ offset += read;
+ count -= read;
+ }
+ if (count > 0 && m_active != Second)
+ {
+ m_active = Second;
+ if (m_active.CanSeek)
+ m_active.Position = 0;
+ int read = m_active.Read (buffer, offset, count);
+ m_position += read;
+ total_read += read;
+ }
+ return total_read;
+ }
+
+ public override long Seek (long offset, SeekOrigin origin)
+ {
+ if (SeekOrigin.Begin == origin)
+ Position = offset;
+ else if (SeekOrigin.Current == origin)
+ Position = m_position + offset;
+ else
+ Position = Length + offset;
+
+ return m_position;
+ }
+
+ bool _disposed = false;
+ protected override void Dispose (bool disposing)
+ {
+ if (!_disposed)
+ {
+ if (disposing)
+ m_second.Dispose();
+ _disposed = true;
+ base.Dispose (disposing);
+ }
+ }
+ }
+}
diff --git a/ArcFormats/TamaSoft/ImageSUR.cs b/ArcFormats/TamaSoft/ImageSUR.cs
new file mode 100644
index 00000000..5f6afcb0
--- /dev/null
+++ b/ArcFormats/TamaSoft/ImageSUR.cs
@@ -0,0 +1,114 @@
+//! \file ImageSUR.cs
+//! \date Tue Sep 20 10:56:45 2016
+//! \brief TamaSoft 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.Tama
+{
+ [Export(typeof(ImageFormat))]
+ public class SurFormat : ImageFormat
+ {
+ public override string Tag { get { return "SUR"; } }
+ public override string Description { get { return "TamaSoft ADV system image"; } }
+ public override uint Signature { get { return 0x52555345; } } // 'ESUR'
+
+ public override ImageMetaData ReadMetaData (Stream stream)
+ {
+ var header = new byte[0x10];
+ if (header.Length != stream.Read (header, 0, header.Length))
+ 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)
+ {
+ var pixels = new byte[info.Width * info.Height * 4];
+ stream.Position = 0x20;
+ UnpackLzss (stream, pixels);
+ return ImageData.Create (info, PixelFormats.Bgra32, null, pixels);
+ }
+
+ public override void Write (Stream file, ImageData image)
+ {
+ throw new System.NotImplementedException ("SurFormat.Write not implemented");
+ }
+
+ ///
+ /// Differs from a common LZSS implementation by frame offset encoding.
+ ///
+ void UnpackLzss (Stream input, byte[] output)
+ {
+ int dst = 0;
+ var frame = new byte[0x1000];
+ int frame_pos = 0xFEE;
+ const int frame_mask = 0xFFF;
+ int ctl = 2;
+ while (dst < output.Length)
+ {
+ ctl >>= 1;
+ if (1 == ctl)
+ {
+ ctl = input.ReadByte();
+ if (-1 == ctl)
+ throw new EndOfStreamException();
+ ctl |= 0x100;
+ }
+ if (0 != (ctl & 1))
+ {
+ byte b = (byte)input.ReadByte();
+ frame[frame_pos++] = b;
+ frame_pos &= frame_mask;
+ output[dst++] = b;
+ }
+ else
+ {
+ int lo = input.ReadByte();
+ int hi = input.ReadByte();
+ if (-1 == hi)
+ throw new EndOfStreamException();
+ int offset = hi >> 4 | lo << 4;
+ int count = Math.Min (3 + (hi & 0xF), output.Length - dst);
+ while (count --> 0)
+ {
+ byte v = frame[offset++];
+ offset &= frame_mask;
+ frame[frame_pos++] = v;
+ frame_pos &= frame_mask;
+ output[dst++] = v;
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/supported.html b/supported.html
index ec14d370..5c65fb4f 100644
--- a/supported.html
+++ b/supported.html
@@ -139,6 +139,7 @@ White ~blanche comme la lune~
Inpyuri -Hito to Anata to Ayakashi to-
Nostradamus ni Kiitemiro♪
Tiny Dungeon ~BLACK and WHITE~
+Tiny Dungeon ~Brave or Slave~
*.dat | - | No | Meteor Silver Bullet |
Chokotto☆Vampire!
@@ -314,6 +315,7 @@ Men at Work 2
Natsu Kagura
|
*.mbl | - | No | Marble |
+Amai Seikatsu -Saikou no Gibo to Saikou no Gishimai-
Assault Angel Canon
Chikatetsu Fuusa Jiken
Eien no Owari ni
@@ -322,6 +324,7 @@ Fuurinkanzan
Gedou Yuusha
Himemiko
Ikusa Otome Valkyrie
+Inmu Gakuen
Mahou Tenshi Misaki
Mahou Tenshi Misaki 2
Ohime-sama wa Tokkun Chuu R! ~Seinaru Mahou Shugyou~
@@ -342,6 +345,7 @@ Ren no Koi
|
*.ald | - | No | Alice Soft |
Boku dake no Hokenshitsu
Daiteikoku
+Momoiro Guardian
Pastel Chime 3 Bind Seeker
Shaman's Sanctuary -Miko no Seiiki-
Tsuma Shibori
@@ -883,6 +887,7 @@ Cafe Junkie
Immoral
Majidashi! Royale ~Finish wa Watashi no Naka de~
MILK Junkies
+Oppai Life
|
*.zbm | amp_ | No |
*.amv | ampV | No |
@@ -1035,6 +1040,7 @@ Cartagra
Kara no Shoujo 2
data.NN ArcNN.dat | - | No | Cyberworks |
+Aneboku ~Onee-chan wa Bijin 3 Shimai~
Aniyome Kyouka-san to Sono Haha Chikako-san
Aru Kazoku no Kankeizu
Chou no Yume ~Futari no Chou~
@@ -1132,7 +1138,12 @@ Triangle Heart 1-2-3
|
*.px | fPX | No |
*.fpk | FPK 0100 | No | MoonhirGames |
Pretty Devil Paradise ~Millium Makai Dakkan Shirei~
+S Sensei no Koto
|
+*.epk | EPK | No | TamaSoft |
+Lost Child
+ |
+*.sur | ESUR | No |
Non-encrypted only