diff --git a/App.xaml.cs b/App.xaml.cs
index ba88a117..4a3e6144 100644
--- a/App.xaml.cs
+++ b/App.xaml.cs
@@ -49,16 +49,6 @@ namespace GARbro.GUI
///
public string InitPath { get; private set; }
- ///
- /// Path to the currently open archive, or empty string if none.
- ///
- public string CurrentPath { get; private set; }
-
- ///
- /// Archive file being browsed, or null.
- ///
- public ArcFile CurrentArchive { get; private set; }
-
void ApplicationStartup (object sender, StartupEventArgs e)
{
#if DEBUG
@@ -90,106 +80,11 @@ namespace GARbro.GUI
if (string.IsNullOrEmpty (InitPath))
InitPath = Directory.GetCurrentDirectory();
-
- CurrentPath = "";
}
void ApplicationExit (object sender, ExitEventArgs e)
{
Settings.Default.Save();
}
-
- public ICollection GetDirectoryList (string path)
- {
- var info = new DirectoryInfo (path);
- var list = new List();
- foreach (var subdir in info.EnumerateDirectories())
- {
- if (0 != (subdir.Attributes & (FileAttributes.Hidden | FileAttributes.System)))
- continue;
- list.Add (new SubDirEntry (subdir.Name));
- }
- foreach (var file in info.EnumerateFiles())
- {
- if (0 != (file.Attributes & (FileAttributes.System)))
- continue;
- var entry = FormatCatalog.Instance.Create (file.Name);
- entry.Size = (uint)Math.Min (file.Length, uint.MaxValue);
- list.Add (entry);
- }
- return list;
- }
-
- public ArcFile GetArchive (string path)
- {
- if (path.Equals (CurrentPath, StringIgnoreCase))
- return CurrentArchive;
- FormatCatalog.Instance.LastError = null;
- var arc = ArcFile.TryOpen (path);
- if (null == arc)
- {
- if (null != FormatCatalog.Instance.LastError)
- throw FormatCatalog.Instance.LastError;
- throw new UnknownFormatException();
- }
- if (null != CurrentArchive)
- CurrentArchive.Dispose();
- CurrentPath = path;
- CurrentArchive = arc;
- return CurrentArchive;
- }
-
- public void ResetCache ()
- {
- if (null != CurrentArchive)
- CurrentArchive.Dispose();
- CurrentArchive = null;
- CurrentPath = "";
- }
-
- // Update UI on demand.
-
- private static DispatcherOperationCallback exitFrameCallback =
- new DispatcherOperationCallback(ExitFrame);
-
- ///
- /// Processes all UI messages currently in the message queue.
- ///
- public static void DoEvents()
- {
- // Create new nested message pump.
- DispatcherFrame nestedFrame = new DispatcherFrame();
-
- // Dispatch a callback to the current message queue, when getting called,
- // this callback will end the nested message loop.
- // note that the priority of this callback should be lower than the that of UI event messages.
- DispatcherOperation exitOperation = Dispatcher.CurrentDispatcher.BeginInvoke(
- DispatcherPriority.Background, exitFrameCallback, nestedFrame);
-
- // pump the nested message loop, the nested message loop will
- // immediately process the messages left inside the message queue.
- Dispatcher.PushFrame(nestedFrame);
-
- // If the "exitFrame" callback doesn't get finished, Abort it.
- if (exitOperation.Status != DispatcherOperationStatus.Completed)
- exitOperation.Abort();
- }
-
- static Object ExitFrame(Object state)
- {
- DispatcherFrame frame = state as DispatcherFrame;
-
- // Exit the nested message loop.
- frame.Continue = false;
- return null;
- }
- }
-
- public class UnknownFormatException : Exception
- {
- public UnknownFormatException () : base (guiStrings.MsgUnknownFormat) { }
- public UnknownFormatException (string path)
- : base (string.Format ("{1}: {0}", guiStrings.MsgUnknownFormat, path))
- { }
}
}
diff --git a/ArcFormats/Properties/AssemblyInfo.cs b/ArcFormats/Properties/AssemblyInfo.cs
index 3809b2ec..2dfab110 100644
--- a/ArcFormats/Properties/AssemblyInfo.cs
+++ b/ArcFormats/Properties/AssemblyInfo.cs
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion ("1.1.10.422")]
-[assembly: AssemblyFileVersion ("1.1.10.422")]
+[assembly: AssemblyVersion ("1.1.12.423")]
+[assembly: AssemblyFileVersion ("1.1.12.423")]
diff --git a/GARbro.sln b/GARbro.sln
index e2c79385..ea6b4b33 100644
--- a/GARbro.sln
+++ b/GARbro.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013
-VisualStudioVersion = 12.0.21005.1
+VisualStudioVersion = 12.0.31101.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GARbro.Console", "Console\GARbro.Console.csproj", "{B966F292-431A-4D8A-A1D3-1EB45048A1D2}"
ProjectSection(ProjectDependencies) = postProject
@@ -17,9 +17,6 @@ EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameRes", "GameRes\GameRes.csproj", "{453C087F-E416-4AE9-8C03-D8760DA0574B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GARbro.GUI", "GARbro.GUI.csproj", "{2935BE57-C4E0-43E7-86DE-C1848C820B19}"
- ProjectSection(ProjectDependencies) = postProject
- {A8865685-27CC-427B-AC38-E48D2AD05DF4} = {A8865685-27CC-427B-AC38-E48D2AD05DF4}
- EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Image.Convert", "Image.Convert\Image.Convert.csproj", "{757EB8B1-F62C-4690-AC3D-DAE4A5576B3E}"
ProjectSection(ProjectDependencies) = postProject
@@ -32,26 +29,22 @@ Global
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {B966F292-431A-4D8A-A1D3-1EB45048A1D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {B966F292-431A-4D8A-A1D3-1EB45048A1D2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B966F292-431A-4D8A-A1D3-1EB45048A1D2}.Debug|Any CPU.ActiveCfg = Release|Any CPU
{B966F292-431A-4D8A-A1D3-1EB45048A1D2}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {B966F292-431A-4D8A-A1D3-1EB45048A1D2}.Release|Any CPU.Build.0 = Release|Any CPU
- {A8865685-27CC-427B-AC38-E48D2AD05DF4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {A8865685-27CC-427B-AC38-E48D2AD05DF4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A8865685-27CC-427B-AC38-E48D2AD05DF4}.Debug|Any CPU.ActiveCfg = Release|Any CPU
+ {A8865685-27CC-427B-AC38-E48D2AD05DF4}.Debug|Any CPU.Build.0 = Release|Any CPU
{A8865685-27CC-427B-AC38-E48D2AD05DF4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A8865685-27CC-427B-AC38-E48D2AD05DF4}.Release|Any CPU.Build.0 = Release|Any CPU
- {453C087F-E416-4AE9-8C03-D8760DA0574B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {453C087F-E416-4AE9-8C03-D8760DA0574B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {453C087F-E416-4AE9-8C03-D8760DA0574B}.Debug|Any CPU.ActiveCfg = Release|Any CPU
+ {453C087F-E416-4AE9-8C03-D8760DA0574B}.Debug|Any CPU.Build.0 = Release|Any CPU
{453C087F-E416-4AE9-8C03-D8760DA0574B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{453C087F-E416-4AE9-8C03-D8760DA0574B}.Release|Any CPU.Build.0 = Release|Any CPU
- {2935BE57-C4E0-43E7-86DE-C1848C820B19}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {2935BE57-C4E0-43E7-86DE-C1848C820B19}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2935BE57-C4E0-43E7-86DE-C1848C820B19}.Debug|Any CPU.ActiveCfg = Release|Any CPU
+ {2935BE57-C4E0-43E7-86DE-C1848C820B19}.Debug|Any CPU.Build.0 = Release|Any CPU
{2935BE57-C4E0-43E7-86DE-C1848C820B19}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2935BE57-C4E0-43E7-86DE-C1848C820B19}.Release|Any CPU.Build.0 = Release|Any CPU
- {757EB8B1-F62C-4690-AC3D-DAE4A5576B3E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {757EB8B1-F62C-4690-AC3D-DAE4A5576B3E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {757EB8B1-F62C-4690-AC3D-DAE4A5576B3E}.Debug|Any CPU.ActiveCfg = Release|Any CPU
{757EB8B1-F62C-4690-AC3D-DAE4A5576B3E}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {757EB8B1-F62C-4690-AC3D-DAE4A5576B3E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/GameRes/ArcFile.cs b/GameRes/ArcFile.cs
index a75100d3..550ec121 100644
--- a/GameRes/ArcFile.cs
+++ b/GameRes/ArcFile.cs
@@ -49,8 +49,6 @@ namespace GameRes
/// Archive contents.
public ICollection Dir { get { return m_dir; } }
- public event EventHandler OverwriteNotify;
-
public ArcFile (ArcView arc, ArchiveFormat impl, ICollection dir)
{
m_arc = arc;
@@ -66,11 +64,11 @@ namespace GameRes
///
public static ArcFile TryOpen (string filename)
{
- var info = new FileInfo (filename);
- if (info.Length < 4)
+ var entry = VFS.FindFile (filename);
+ if (entry.Size < 4)
return null;
var ext = new Lazy (() => Path.GetExtension (filename).TrimStart ('.').ToLowerInvariant());
- var file = new ArcView (filename);
+ var file = VFS.OpenView (entry);
try
{
uint signature = file.View.ReadUInt32 (0);
@@ -191,15 +189,6 @@ namespace GameRes
}
}
- ///
- /// Create file corresponding to within current directory and open
- /// it for writing.
- ///
- public Stream CreateFile (Entry entry)
- {
- return ArchiveFormat.CreateFile (entry.Name);
- }
-
public IFileSystem CreateFileSystem ()
{
if (m_interface.IsHierarchic)
@@ -229,98 +218,4 @@ namespace GameRes
}
#endregion
}
-
- public class OverwriteEventArgs : EventArgs
- {
- public string Filename { get; set; }
- public bool Overwrite { get; set; }
- }
-
- public class AppendStream : System.IO.Stream
- {
- private Stream m_base;
- private long m_start_pos;
-
- public override bool CanRead { get { return true; } }
- public override bool CanSeek { get { return true; } }
- public override bool CanWrite { get { return true; } }
- public override long Length { get { return m_base.Length - m_start_pos; } }
- public override long Position
- {
- get { return m_base.Position - m_start_pos; }
- set { m_base.Position = Math.Max (m_start_pos+value, m_start_pos); }
- }
-
- public AppendStream (System.IO.Stream file)
- {
- m_base = file;
- m_start_pos = m_base.Seek (0, SeekOrigin.End);
- }
-
- public AppendStream (System.IO.Stream file, long offset)
- {
- m_base = file;
- m_start_pos = m_base.Seek (offset, SeekOrigin.Begin);
- }
-
- public Stream BaseStream { get { return m_base; } }
-
- public override void Flush()
- {
- m_base.Flush();
- }
-
- public override long Seek (long offset, SeekOrigin origin)
- {
- if (SeekOrigin.Begin == origin)
- {
- offset = Math.Max (offset + m_start_pos, m_start_pos);
- }
- long position = m_base.Seek (offset, origin);
- if (position < m_start_pos)
- {
- m_base.Seek (m_start_pos, SeekOrigin.Begin);
- position = m_start_pos;
- }
- return position - m_start_pos;
- }
-
- public override void SetLength (long length)
- {
- if (length < 0)
- length = 0;
- m_base.SetLength (length + m_start_pos);
- }
-
- public override int Read (byte[] buffer, int offset, int count)
- {
- return m_base.Read (buffer, offset, count);
- }
-
- public override int ReadByte ()
- {
- return m_base.ReadByte();
- }
-
- public override void Write (byte[] buffer, int offset, int count)
- {
- m_base.Write (buffer, offset, count);
- }
-
- public override void WriteByte (byte value)
- {
- m_base.WriteByte (value);
- }
-
- bool disposed = false;
- protected override void Dispose (bool disposing)
- {
- if (!disposed)
- {
- m_base = null;
- disposed = true;
- base.Dispose (disposing);
- }
- }
- }
}
diff --git a/GameRes/FileSystem.cs b/GameRes/FileSystem.cs
index e4ea47dd..32d2b85e 100644
--- a/GameRes/FileSystem.cs
+++ b/GameRes/FileSystem.cs
@@ -28,16 +28,28 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
+using GameRes.Strings;
namespace GameRes
{
public interface IFileSystem : IDisposable
{
///
- /// Open file for reading.
+ /// Returns entry corresponding to the given filename within filesystem.
+ ///
+ /// File is not found.
+ Entry FindFile (string filename);
+
+ ///
+ /// Open file for reading as stream.
///
Stream OpenStream (Entry entry);
+ Stream OpenSeekableStream (Entry entry);
+
+ ///
+ /// Open file for reading as memory-mapped view.
+ ///
ArcView OpenView (Entry entry);
///
@@ -47,7 +59,7 @@ namespace GameRes
///
/// Recursively enumerates files in the current directory and its subdirectories.
- /// Subdirectory entries are omitted.
+ /// Subdirectory entries are omitted from resulting set.
///
IEnumerable GetFilesRecursive ();
@@ -73,6 +85,15 @@ namespace GameRes
set { Directory.SetCurrentDirectory (value); }
}
+ public Entry FindFile (string filename)
+ {
+ var attr = File.GetAttributes (filename);
+ if ((attr & FileAttributes.Directory) == FileAttributes.Directory)
+ return new SubDirEntry (filename);
+ else
+ return EntryFromFileInfo (new FileInfo (filename));
+ }
+
public IEnumerable GetFiles ()
{
var info = new DirectoryInfo (CurrentDirectory);
@@ -84,7 +105,7 @@ namespace GameRes
}
foreach (var file in info.EnumerateFiles())
{
- if (0 != (file.Attributes & (FileAttributes.Hidden | FileAttributes.System)))
+ if (0 != (file.Attributes & FileAttributes.System))
continue;
yield return EntryFromFileInfo (file);
}
@@ -113,6 +134,11 @@ namespace GameRes
return File.OpenRead (entry.Name);
}
+ public Stream OpenSeekableStream (Entry entry)
+ {
+ return OpenStream (entry);
+ }
+
public ArcView OpenView (Entry entry)
{
return new ArcView (entry.Name);
@@ -126,7 +152,10 @@ namespace GameRes
public class FlatArchiveFileSystem : IFileSystem
{
- protected ArcFile m_arc;
+ protected readonly ArcFile m_arc;
+ protected readonly Dictionary m_dir;
+
+ public ArcFile Source { get { return m_arc; } }
public virtual string CurrentDirectory
{
@@ -146,6 +175,11 @@ namespace GameRes
public FlatArchiveFileSystem (ArcFile arc)
{
m_arc = arc;
+ m_dir = new Dictionary (arc.Dir.Count, StringComparer.InvariantCultureIgnoreCase);
+ foreach (var entry in arc.Dir)
+ {
+ m_dir.Add (entry.Name, entry);
+ }
}
public Stream OpenStream (Entry entry)
@@ -153,11 +187,24 @@ namespace GameRes
return m_arc.OpenEntry (entry);
}
+ public Stream OpenSeekableStream (Entry entry)
+ {
+ return m_arc.OpenSeekableEntry (entry);
+ }
+
public ArcView OpenView (Entry entry)
{
return m_arc.OpenView (entry);
}
+ public virtual Entry FindFile (string filename)
+ {
+ Entry entry = null;
+ if (!m_dir.TryGetValue (filename, out entry))
+ throw new FileNotFoundException();
+ return entry;
+ }
+
public virtual IEnumerable GetFiles ()
{
return m_arc.Dir;
@@ -211,6 +258,16 @@ namespace GameRes
set { ChDir (value); }
}
+ public override Entry FindFile (string filename)
+ {
+ Entry entry = null;
+ if (m_dir.TryGetValue (filename, out entry))
+ return entry;
+ if (m_dir.Keys.Any (n => n.StartsWith (filename + PathDelimiter)))
+ return new SubDirEntry (filename);
+ throw new FileNotFoundException();
+ }
+
static readonly Regex path_re = new Regex (@"\G[/\\]?([^/\\]+)([/\\])");
public override IEnumerable GetFiles ()
@@ -300,4 +357,188 @@ namespace GameRes
m_cwd = new_path;
}
}
+
+ public sealed class FileSystemStack : IDisposable
+ {
+ Stack m_fs_stack = new Stack();
+ Stack m_arc_name_stack = new Stack();
+
+ public IEnumerable All { get { return m_fs_stack; } }
+
+ public IFileSystem Top { get { return m_fs_stack.Peek(); } }
+ public int Count { get { return m_fs_stack.Count; } }
+ public IEnumerable ArcStack { get { return m_arc_name_stack; } }
+
+ public ArcFile CurrentArchive { get; private set; }
+ private IFileSystem LastVisitedArc { get; set; }
+ private string LastVisitedPath { get; set; }
+
+ public FileSystemStack ()
+ {
+ m_fs_stack.Push (new PhysicalFileSystem());
+ }
+
+ public void ChDir (Entry entry)
+ {
+ if (entry is SubDirEntry)
+ {
+ if (1 == m_fs_stack.Count)
+ {
+ Top.CurrentDirectory = entry.Name;
+ return;
+ }
+ if (".." == entry.Name && string.IsNullOrEmpty (Top.CurrentDirectory))
+ {
+ Pop();
+ return;
+ }
+ }
+ if (entry.Name == LastVisitedPath && null != LastVisitedArc)
+ {
+ Push (LastVisitedPath, LastVisitedArc);
+ return;
+ }
+ Flush();
+ var arc = ArcFile.TryOpen (entry.Name);
+ if (null == arc)
+ throw new UnknownFormatException();
+ try
+ {
+ Push (entry.Name, arc.CreateFileSystem());
+ CurrentArchive = arc;
+ }
+ catch
+ {
+ arc.Dispose();
+ throw;
+ }
+ }
+
+ private void Push (string path, IFileSystem fs)
+ {
+ m_fs_stack.Push (fs);
+ m_arc_name_stack.Push (path);
+ }
+
+ private void Pop ()
+ {
+ if (m_fs_stack.Count > 1)
+ {
+ Flush();
+ LastVisitedArc = m_fs_stack.Pop();
+ LastVisitedPath = m_arc_name_stack.Pop();
+ if (m_fs_stack.Count > 1 && m_fs_stack.Peek() is FlatArchiveFileSystem)
+ CurrentArchive = (m_fs_stack.Peek() as FlatArchiveFileSystem).Source;
+ else
+ CurrentArchive = null;
+ }
+ }
+
+ public void Flush ()
+ {
+ if (LastVisitedArc != null)
+ {
+ LastVisitedArc.Dispose();
+ LastVisitedArc = null;
+ LastVisitedPath = null;
+ }
+ }
+
+ private bool _disposed = false;
+ public void Dispose ()
+ {
+ if (!_disposed)
+ {
+ Flush();
+ foreach (var fs in m_fs_stack.Reverse())
+ fs.Dispose();
+ _disposed = true;
+ }
+ GC.SuppressFinalize (this);
+ }
+ }
+
+ public static class VFS
+ {
+ private static FileSystemStack m_vfs = new FileSystemStack();
+
+ public static IFileSystem Top { get { return m_vfs.Top; } }
+ public static bool IsVirtual { get { return m_vfs.Count > 1; } }
+ public static int Count { get { return m_vfs.Count; } }
+
+ public static ArcFile CurrentArchive { get { return m_vfs.CurrentArchive; } }
+
+ private static string[] m_top_path = new string[1];
+
+ public static IEnumerable FullPath
+ {
+ get
+ {
+ m_top_path[0] = Top.CurrentDirectory;
+ if (1 == Count)
+ return m_top_path;
+ else
+ return m_vfs.ArcStack.Concat (m_top_path);
+ }
+ set
+ {
+ if (!value.Any())
+ return;
+ var new_vfs = new FileSystemStack();
+ var desired = value.ToArray();
+ for (int i = 0; i < desired.Length-1; ++i)
+ new_vfs.ChDir (new_vfs.Top.FindFile (desired[i]));
+ new_vfs.Top.CurrentDirectory = desired.Last();
+ m_vfs.Dispose();
+ m_vfs = new_vfs;
+ }
+ }
+
+ public static Entry FindFile (string filename)
+ {
+ if (".." == filename)
+ return new SubDirEntry ("..");
+ return m_vfs.Top.FindFile (filename);
+ }
+
+ public static Stream OpenStream (Entry entry)
+ {
+ return m_vfs.Top.OpenStream (entry);
+ }
+
+ public static Stream OpenSeekableStream (Entry entry)
+ {
+ return m_vfs.Top.OpenSeekableStream (entry);
+ }
+
+ public static ArcView OpenView (Entry entry)
+ {
+ return m_vfs.Top.OpenView (entry);
+ }
+
+ public static void ChDir (Entry entry)
+ {
+ m_vfs.ChDir (entry);
+ }
+
+ public static void ChDir (string path)
+ {
+ m_vfs.ChDir (FindFile (path));
+ }
+
+ public static void Flush ()
+ {
+ m_vfs.Flush();
+ }
+
+ public static IEnumerable GetFiles ()
+ {
+ return m_vfs.Top.GetFiles();
+ }
+ }
+
+ public class UnknownFormatException : FileFormatException
+ {
+ public UnknownFormatException () : base (garStrings.MsgUnknownFormat) { }
+ }
}
diff --git a/GameRes/GameRes.cs b/GameRes/GameRes.cs
index 3a6f5ec9..373033d7 100644
--- a/GameRes/GameRes.cs
+++ b/GameRes/GameRes.cs
@@ -261,6 +261,12 @@ namespace GameRes
public ResourceOptions Options { get; set; }
}
+ public class OverwriteEventArgs : EventArgs
+ {
+ public string Filename { get; set; }
+ public bool Overwrite { get; set; }
+ }
+
public sealed class FormatCatalog
{
private static readonly FormatCatalog m_instance = new FormatCatalog();
diff --git a/GameRes/Properties/AssemblyInfo.cs b/GameRes/Properties/AssemblyInfo.cs
index 1ce73221..9ed6d3e2 100644
--- a/GameRes/Properties/AssemblyInfo.cs
+++ b/GameRes/Properties/AssemblyInfo.cs
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion ("1.1.7.90")]
-[assembly: AssemblyFileVersion ("1.1.7.90")]
+[assembly: AssemblyVersion ("1.1.9.91")]
+[assembly: AssemblyFileVersion ("1.1.9.91")]
diff --git a/GameRes/Strings/garStrings.Designer.cs b/GameRes/Strings/garStrings.Designer.cs
index 7cdce5cd..0baa50f2 100644
--- a/GameRes/Strings/garStrings.Designer.cs
+++ b/GameRes/Strings/garStrings.Designer.cs
@@ -1,7 +1,7 @@
//------------------------------------------------------------------------------
//
// This code was generated by a tool.
-// Runtime Version:4.0.30319.18444
+// Runtime Version:4.0.30319.34209
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
@@ -104,5 +104,14 @@ namespace GameRes.Strings {
return ResourceManager.GetString("MsgUnknownEncryption", resourceCulture);
}
}
+
+ ///
+ /// Looks up a localized string similar to file could not be opened as resource archive.
+ ///
+ public static string MsgUnknownFormat {
+ get {
+ return ResourceManager.GetString("MsgUnknownFormat", resourceCulture);
+ }
+ }
}
}
diff --git a/GameRes/Strings/garStrings.resx b/GameRes/Strings/garStrings.resx
index 480912c6..dcfe9a63 100644
--- a/GameRes/Strings/garStrings.resx
+++ b/GameRes/Strings/garStrings.resx
@@ -132,4 +132,7 @@
Unknown encryption scheme
+
+ file could not be opened as resource archive
+
\ No newline at end of file
diff --git a/GameRes/Strings/garStrings.ru-RU.resx b/GameRes/Strings/garStrings.ru-RU.resx
index c8040a17..04b4d9e3 100644
--- a/GameRes/Strings/garStrings.ru-RU.resx
+++ b/GameRes/Strings/garStrings.ru-RU.resx
@@ -132,4 +132,7 @@
Неизвестный метод шифрования
+
+ файл не может быть открыт как архив ресурсов
+
\ No newline at end of file
diff --git a/GarConvert.cs b/GarConvert.cs
index 72ab5cd4..cadbd6c5 100644
--- a/GarConvert.cs
+++ b/GarConvert.cs
@@ -68,7 +68,7 @@ namespace GARbro.GUI
}
try
{
- Directory.SetCurrentDirectory (ViewModel.Path);
+ Directory.SetCurrentDirectory (ViewModel.Path.First());
var converter = new GarConvertMedia (this);
converter.IgnoreErrors = convert_dialog.IgnoreErrors.IsChecked ?? false;
converter.Convert (source, format);
diff --git a/GarExtract.cs b/GarExtract.cs
index 49b16e72..8d619c65 100644
--- a/GarExtract.cs
+++ b/GarExtract.cs
@@ -34,6 +34,7 @@ using System.Windows.Input;
using System.Windows.Media.Imaging;
using Ookii.Dialogs.Wpf;
using GameRes;
+using GameRes.Strings;
using GARbro.GUI.Strings;
using GARbro.GUI.Properties;
@@ -58,11 +59,12 @@ namespace GARbro.GUI
string destination = Settings.Default.appLastDestination;
if (!Directory.Exists (destination))
destination = "";
- if (!ViewModel.IsArchive)
+ var vm = ViewModel;
+ if (!vm.IsArchive)
{
if (!entry.IsDirectory)
{
- var arc_dir = CurrentPath;
+ var arc_dir = vm.Path.First();
var source = Path.Combine (arc_dir, entry.Name);
if (string.IsNullOrEmpty (destination))
destination = arc_dir;
@@ -73,13 +75,13 @@ namespace GARbro.GUI
extractor.ExtractAll (destination);
}
}
- else if (null != m_app.CurrentArchive)
+ else if (vm.Path.Skip (1).Any())
{
- var vm = ViewModel as ArchiveViewModel;
if (string.IsNullOrEmpty (destination))
- destination = Path.GetDirectoryName (vm.Path);
- extractor = new GarExtract (this, vm.Path, m_app.CurrentArchive);
- if (null == entry || (entry.Name == ".." && vm.SubDir == "")) // root entry
+ destination = Path.GetDirectoryName (vm.Path.First());
+ var archive_name = vm.Path.Reverse().Skip (1).First();
+ extractor = new GarExtract (this, archive_name, VFS.CurrentArchive);
+ if (null == entry || (entry.Name == ".." && string.IsNullOrEmpty (vm.Path.Last()))) // root entry
extractor.ExtractAll (destination);
else
extractor.Extract (entry, destination);
@@ -132,7 +134,7 @@ namespace GARbro.GUI
if (FormatCatalog.Instance.LastError != null)
error_message = FormatCatalog.Instance.LastError.Message;
else
- error_message = guiStrings.MsgUnknownFormat;
+ error_message = garStrings.MsgUnknownFormat;
throw new OperationCanceledException (string.Format ("{1}: {0}", error_message, m_arc_name));
}
m_should_dispose = true;
diff --git a/ImagePreview.cs b/ImagePreview.cs
index af776547..117ccaf9 100644
--- a/ImagePreview.cs
+++ b/ImagePreview.cs
@@ -75,14 +75,13 @@ namespace GARbro.GUI
class PreviewFile
{
- public string Path { get; set; }
+ public IEnumerable Path { get; set; }
public string Name { get; set; }
- public Entry Entry { get; set; }
- public ArcFile Archive { get; set; }
+ public Entry Entry { get; set; }
- public bool IsEqual (string path, string name)
+ public bool IsEqual (IEnumerable path, string name)
{
- return path.Equals (Path) && name.Equals (Name);
+ return Path != null && path.SequenceEqual (Path) && name.Equals (Name);
}
}
@@ -167,8 +166,6 @@ namespace GARbro.GUI
ActiveViewer = ImageView;
return;
}
- if (vm.IsArchive)
- m_current_preview.Archive = m_app.CurrentArchive;
if ("image" != entry.Type)
LoadPreviewText (m_current_preview);
else if (!m_preview_worker.IsBusy)
@@ -193,15 +190,7 @@ namespace GARbro.GUI
Stream OpenPreviewStream (PreviewFile preview)
{
- if (null == preview.Archive)
- {
- string filename = Path.Combine (preview.Path, preview.Name);
- return File.OpenRead (filename);
- }
- else
- {
- return preview.Archive.OpenSeekableEntry (preview.Entry);
- }
+ return VFS.OpenSeekableStream (preview.Entry);
}
void LoadPreviewText (PreviewFile preview)
diff --git a/MainWindow.xaml.cs b/MainWindow.xaml.cs
index 76348aa2..213bc461 100644
--- a/MainWindow.xaml.cs
+++ b/MainWindow.xaml.cs
@@ -223,16 +223,15 @@ namespace GARbro.GUI
StopWatchDirectoryChanges();
var cvs = this.Resources["ListViewSource"] as CollectionViewSource;
cvs.Source = value;
- pathLine.Text = value.Path;
+ pathLine.Text = value.Path.Last();
- if (value.IsArchive)
- PushRecentFile (value.Path);
+ if (value.IsArchive && !value.Path.Skip (2).Any())
+ PushRecentFile (value.Path.First());
lv_Sort (SortMode, m_lvSortDirection);
- if (!value.IsArchive && !string.IsNullOrEmpty (value.Path))
+ if (!value.IsArchive && !string.IsNullOrEmpty (value.Path.First()))
{
- Directory.SetCurrentDirectory (value.Path);
- WatchDirectoryChanges (value.Path);
+ WatchDirectoryChanges (value.Path.First());
}
CurrentDirectory.UpdateLayout();
}
@@ -240,16 +239,13 @@ namespace GARbro.GUI
DirectoryViewModel GetNewViewModel (string path)
{
- path = Path.GetFullPath (path);
- if (Directory.Exists (path))
- {
- return new DirectoryViewModel (path, m_app.GetDirectoryList (path));
- }
- else
- {
+ if (!VFS.IsVirtual)
+ path = Path.GetFullPath (path);
+ var entry = VFS.FindFile (path);
+ if (!(entry is SubDirEntry))
SetBusyState();
- return new ArchiveViewModel (path, m_app.GetArchive (path));
- }
+ VFS.ChDir (entry);
+ return new DirectoryViewModel (VFS.FullPath, VFS.GetFiles(), VFS.IsVirtual);
}
private bool m_busy_state = false;
@@ -293,7 +289,7 @@ namespace GARbro.GUI
catch (Exception X)
{
PopupError (X.Message, guiStrings.MsgErrorOpening);
- return new DirectoryViewModel ("", new Entry[0]);
+ return new DirectoryViewModel (new string[] { "" }, new Entry[0], false);
}
}
@@ -323,13 +319,14 @@ namespace GARbro.GUI
public void ResumeWatchDirectoryChanges ()
{
- m_watcher.EnableRaisingEvents = true;
+ m_watcher.EnableRaisingEvents = !ViewModel.IsArchive;
}
private void InvokeRefreshView (object source, FileSystemEventArgs e)
{
var watcher = source as FileSystemWatcher;
- if (watcher.Path == ViewModel.Path)
+ var vm = ViewModel;
+ if (!vm.IsArchive && vm.Path.First() == watcher.Path)
{
watcher.EnableRaisingEvents = false;
Dispatcher.Invoke (RefreshView);
@@ -632,7 +629,7 @@ namespace GARbro.GUI
#region Navigation history implementation
- internal string CurrentPath { get { return ViewModel.Path; } }
+ internal string CurrentPath { get { return ViewModel.Path.First(); } }
HistoryStack m_history = new HistoryStack();
@@ -644,12 +641,12 @@ namespace GARbro.GUI
public bool SetCurrentPosition (DirectoryPosition pos)
{
- var vm = TryCreateViewModel (pos.Path);
- if (null == vm)
- return false;
try
{
- vm.SetPosition (pos);
+ VFS.FullPath = pos.Path;
+ var vm = TryCreateViewModel (pos.Path.Last());
+ if (null == vm)
+ return false;
ViewModel = vm;
if (null != pos.Item)
lv_SelectItem (pos.Item);
@@ -670,7 +667,7 @@ namespace GARbro.GUI
public void ChangePosition (DirectoryPosition new_pos)
{
var current = GetCurrentPosition();
- if (current.Path != new_pos.Path || current.ArchivePath != new_pos.ArchivePath)
+ if (!current.Path.SequenceEqual (new_pos.Path))
SaveCurrentPosition();
SetCurrentPosition (new_pos);
}
@@ -722,8 +719,8 @@ namespace GARbro.GUI
var vm = GetNewViewModel (filename);
SaveCurrentPosition();
ViewModel = vm;
- if (null != m_app.CurrentArchive)
- SetStatusText (m_app.CurrentArchive.Description);
+ if (null != VFS.CurrentArchive)
+ SetStatusText (VFS.CurrentArchive.Description);
lv_SelectItem (0);
}
catch (OperationCanceledException X)
@@ -766,48 +763,37 @@ namespace GARbro.GUI
PlayFile (entry.Source);
return;
}
- if (vm.IsArchive) // tried to open file inside archive
- {
- var arc_vm = vm as ArchiveViewModel;
- if (!("" == arc_vm.SubDir && ".." == entry.Name))
- {
- OpenArchiveEntry (arc_vm, entry);
- return;
- }
- }
OpenDirectoryEntry (vm, entry);
}
private void OpenDirectoryEntry (DirectoryViewModel vm, EntryViewModel entry)
{
- string old_dir = vm.Path;
- string new_dir = Path.Combine (old_dir, entry.Name);
+ string old_dir = vm.Path.Last();
+ string new_dir = entry.Source.Name;
+ if (!vm.IsArchive && ".." == new_dir)
+ new_dir = Path.Combine (old_dir, entry.Name);
Trace.WriteLine (new_dir, "OpenDirectoryEntry");
+ int old_fs_count = VFS.Count;
vm = TryCreateViewModel (new_dir);
if (null == vm)
{
-// if (entry.Type != "archive")
-// SystemOpen (new_dir);
return;
}
SaveCurrentPosition();
ViewModel = vm;
- if (vm.IsArchive && null != m_app.CurrentArchive)
- SetStatusText (string.Format ("{0}: {1}", m_app.CurrentArchive.Description,
- Localization.Format ("MsgFiles", m_app.CurrentArchive.Dir.Count())));
+ if (VFS.Count > old_fs_count && null != VFS.CurrentArchive)
+ SetStatusText (string.Format ("{0}: {1}", VFS.CurrentArchive.Description,
+ Localization.Format ("MsgFiles", VFS.CurrentArchive.Dir.Count())));
else
SetStatusText ("");
- var old_parent = Directory.GetParent (old_dir);
- if (null != old_parent && vm.Path == old_parent.FullName)
- {
+
+ if (".." == entry.Name)
lv_SelectItem (Path.GetFileName (old_dir));
- }
else
- {
lv_SelectItem (0);
- }
}
+ /*
private void OpenArchiveEntry (ArchiveViewModel vm, EntryViewModel entry)
{
if (entry.IsDirectory)
@@ -829,14 +815,11 @@ namespace GARbro.GUI
}
}
}
+ */
Stream OpenEntry (Entry entry)
{
- var vm = ViewModel;
- if (vm.IsArchive)
- return m_app.CurrentArchive.OpenEntry (entry);
- else
- return File.OpenRead (Path.Combine (vm.Path, entry.Name));
+ return VFS.OpenStream (entry);
}
WaveOutEvent m_audio_device;
@@ -935,7 +918,7 @@ namespace GARbro.GUI
public void RefreshView ()
{
- m_app.ResetCache();
+ VFS.Flush();
var pos = GetCurrentPosition();
SetCurrentPosition (pos);
}
@@ -974,7 +957,7 @@ namespace GARbro.GUI
this.IsEnabled = false;
try
{
- m_app.ResetCache();
+ VFS.Flush();
ResetPreviewPane();
if (!items.Skip (1).Any()) // items.Count() == 1
{
diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs
index a6a123e1..cc51191d 100644
--- a/Properties/AssemblyInfo.cs
+++ b/Properties/AssemblyInfo.cs
@@ -51,5 +51,5 @@ using System.Windows;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion ("1.1.6.659")]
-[assembly: AssemblyFileVersion ("1.1.6.659")]
+[assembly: AssemblyVersion ("1.1.8.660")]
+[assembly: AssemblyFileVersion ("1.1.8.660")]
diff --git a/Strings/guiStrings.Designer.cs b/Strings/guiStrings.Designer.cs
index d3b7b4d0..ae8586f9 100644
--- a/Strings/guiStrings.Designer.cs
+++ b/Strings/guiStrings.Designer.cs
@@ -729,15 +729,6 @@ namespace GARbro.GUI.Strings {
}
}
- ///
- /// Looks up a localized string similar to file could not be opened as resource archive.
- ///
- public static string MsgUnknownFormat {
- get {
- return ResourceManager.GetString("MsgUnknownFormat", resourceCulture);
- }
- }
-
///
/// Looks up a localized string similar to Version {0}.
///
diff --git a/Strings/guiStrings.resx b/Strings/guiStrings.resx
index 279e7917..9ed61ce3 100644
--- a/Strings/guiStrings.resx
+++ b/Strings/guiStrings.resx
@@ -243,9 +243,6 @@
unable to interpret image format
-
- file could not be opened as resource archive
-
Version {0}
diff --git a/Strings/guiStrings.ru-RU.resx b/Strings/guiStrings.ru-RU.resx
index e616ec0d..2910a931 100644
--- a/Strings/guiStrings.ru-RU.resx
+++ b/Strings/guiStrings.ru-RU.resx
@@ -237,9 +237,6 @@
не удалось интерпретировать формат изображения
-
- файл не может быть открыт как архив ресурсов
-
Версия {0}
diff --git a/ViewModel.cs b/ViewModel.cs
index 96e3bc51..5e75a0ba 100644
--- a/ViewModel.cs
+++ b/ViewModel.cs
@@ -41,20 +41,22 @@ namespace GARbro.GUI
{
public class DirectoryViewModel : ObservableCollection
{
- public string Path { get; private set; }
- public ICollection Source { get; private set; }
- public virtual bool IsArchive { get { return false; } }
+ public IEnumerable Path { get; private set; }
+ public IEnumerable Source { get; private set; }
+ public bool IsArchive { get; private set; }
- public DirectoryViewModel (string path, ICollection filelist)
+ public DirectoryViewModel (IEnumerable path, IEnumerable filelist, bool is_archive)
{
Path = path;
Source = filelist;
+ IsArchive = is_archive;
ImportFromSource();
}
- protected virtual void ImportFromSource ()
+ protected void ImportFromSource ()
{
- if (!string.IsNullOrEmpty (Path) && null != Directory.GetParent (Path))
+ var last_dir = Path.Last();
+ if (IsArchive || !string.IsNullOrEmpty (last_dir) && null != Directory.GetParent (last_dir))
{
Add (new EntryViewModel (new SubDirEntry (".."), -2));
}
@@ -80,6 +82,7 @@ namespace GARbro.GUI
}
}
+ /*
public class ArchiveViewModel : DirectoryViewModel
{
public override bool IsArchive { get { return true; } }
@@ -212,6 +215,7 @@ namespace GARbro.GUI
base.OnCollectionChanged(e);
}
}
+ */
public class EntryViewModel : INotifyPropertyChanged
{
@@ -332,24 +336,18 @@ namespace GARbro.GUI
///
public class DirectoryPosition
{
- public string Path { get; set; }
- public string ArchivePath { get; set; }
- public string Item { get; set; }
+ public IEnumerable Path { get; set; }
+ public string Item { get; set; }
public DirectoryPosition (DirectoryViewModel vm, EntryViewModel item)
{
Path = vm.Path;
Item = null != item ? item.Name : null;
- if (vm.IsArchive)
- ArchivePath = (vm as ArchiveViewModel).SubDir;
- else
- ArchivePath = "";
}
public DirectoryPosition (string filename)
{
- Path = System.IO.Path.GetDirectoryName (filename);
- ArchivePath = "";
+ Path = new string[] { System.IO.Path.GetDirectoryName (filename) };
Item = System.IO.Path.GetFileName (filename);
}
}