Initial commit.

This commit is contained in:
Poddav 2014-07-21 23:26:28 +04:00
commit e208029dd3
102 changed files with 14809 additions and 0 deletions

6
.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
bin
obj
tags
*.exe
*.suo
*;*

100
AboutBox.xaml Normal file
View File

@ -0,0 +1,100 @@
<!-- Game Resource browser
Copyright (C) 2014 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.
-->
<w:ModalWindow x:Class="GARbro.GUI.AboutBox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:GARbro.GUI"
xmlns:w="clr-namespace:Rnd.Windows"
xmlns:s="clr-namespace:GARbro.GUI.Strings"
Title="{x:Static s:guiStrings.TextAboutTitle}" Height="306" Width="475" ResizeMode="NoResize"
Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"
ShowInTaskbar="False" WindowStartupLocation="CenterOwner">
<Window.Resources>
<local:BooleanToVisibiltyConverter x:Key="guiBoolToVisibilityConverter" />
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="43*" />
<ColumnDefinition Width="74*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<StackPanel Grid.Column="0" Grid.Row="0" Grid.RowSpan="4" Margin="10,10,10,67.304"
DataContext="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:AboutBox}}}">
<Label Content="{Binding Path=AssemblyTitle, Mode=OneWay}" />
<Label Content="{Binding Path=VersionString, Mode=OneWay}" />
<Label Content="{Binding Path=AssemblyCopyright, Mode=OneWay}" />
</StackPanel>
<Button Grid.Row="3" VerticalAlignment="Bottom" HorizontalAlignment="Left" IsDefault="true"
Content="{x:Static s:guiStrings.ButtonOK}" Margin="10,0,0,10" Width="70" Click="Button_Click" IsCancel="True" Height="21"/>
<Grid Grid.Column="1" Grid.Row="0" Grid.RowSpan="2" Margin="10,8,10,6">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock Text="{x:Static s:guiStrings.TextAboutSupportedArchives}" Grid.Row="0" Margin="0" />
<Border Grid.Row="1" BorderThickness="1" BorderBrush="Black" VerticalAlignment="Stretch" Margin="0" SnapsToDevicePixels="True">
<ScrollViewer Grid.Row="1" Margin="0" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled"
Background="{DynamicResource {x:Static SystemColors.ControlLightLightBrushKey}}"
BorderThickness="1" BorderBrush="Black">
<ItemsControl Name="ArchiveFormats">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Tag}" Margin="3,0,5,0" />
<TextBlock Text="{Binding Description}" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Border>
</Grid>
<Grid Grid.Column="1" Grid.Row="2" Grid.RowSpan="2" Margin="10,2,10,10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="{x:Static s:guiStrings.TextAboutSupportedImages}" Margin="0" />
<Border Grid.Row="1" BorderThickness="1" BorderBrush="Black" VerticalAlignment="Stretch" Margin="0" SnapsToDevicePixels="True">
<ScrollViewer VerticalAlignment="Stretch" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" Margin="0" Background="{DynamicResource {x:Static SystemColors.ControlLightLightBrushKey}}" BorderThickness="1" BorderBrush="Black">
<ItemsControl Name="ImageFormats">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Tag}" Margin="3,0,5,0" />
<TextBlock Text="{x:Static s:guiStrings.TextAboutBuiltin}" Margin="0,0,5,0" Visibility="{Binding IsBuiltin, Converter={StaticResource guiBoolToVisibilityConverter}}"/>
<TextBlock Text="{Binding Description}" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Border>
</Grid>
</Grid>
</w:ModalWindow>

213
AboutBox.xaml.cs Normal file
View File

@ -0,0 +1,213 @@
/// Game Resource browser
//
// Copyright (C) 2014 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.Reflection;
using System.Windows;
using System.Windows.Data;
using GARbro.GUI.Properties;
using GARbro.GUI.Strings;
namespace GARbro.GUI
{
/// <summary>
/// Interaction logic for AboutBox.xaml
/// </summary>
public partial class AboutBox : Rnd.Windows.ModalWindow
{
public AboutBox()
{
InitializeComponent();
ArchiveFormats.ItemsSource = GameRes.FormatCatalog.Instance.ArcFormats;
ImageFormats.ItemsSource = GameRes.FormatCatalog.Instance.ImageFormats;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
this.Close();
}
#region Assembly Attribute Accessors
public string AssemblyTitle
{
get
{
object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyTitleAttribute), false);
if (attributes.Length > 0)
{
AssemblyTitleAttribute titleAttribute = (AssemblyTitleAttribute)attributes[0];
if (titleAttribute.Title != "")
{
return titleAttribute.Title;
}
}
return System.IO.Path.GetFileNameWithoutExtension(Assembly.GetExecutingAssembly().CodeBase);
}
}
public string VersionString
{
get
{
return string.Format (guiStrings.MsgVersion, AssemblyVersion);
}
}
public string AssemblyVersion
{
get
{
return Assembly.GetExecutingAssembly().GetName().Version.ToString();
}
}
public string AssemblyDescription
{
get
{
object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyDescriptionAttribute), false);
if (attributes.Length == 0)
{
return "";
}
return ((AssemblyDescriptionAttribute)attributes[0]).Description;
}
}
public string AssemblyProduct
{
get
{
object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyProductAttribute), false);
if (attributes.Length == 0)
{
return "";
}
return ((AssemblyProductAttribute)attributes[0]).Product;
}
}
public string AssemblyCopyright
{
get
{
object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyCopyrightAttribute), false);
if (attributes.Length == 0)
{
return "";
}
return ((AssemblyCopyrightAttribute)attributes[0]).Copyright;
}
}
public string AssemblyCompany
{
get
{
object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyCompanyAttribute), false);
if (attributes.Length == 0)
{
return "";
}
return ((AssemblyCompanyAttribute)attributes[0]).Company;
}
}
#endregion
}
public class BooleanToVisibiltyConverter : IValueConverter
{
/// <summary>Convert a boolean value to a Visibility value</summary>
public object Convert (object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
bool isVisible = (bool)value;
// If visibility is inverted by the converter parameter, then invert our value
if (IsVisibilityInverted (parameter))
isVisible = !isVisible;
return (isVisible ? Visibility.Visible : Visibility.Collapsed);
}
/// <summary>
/// Determine the visibility mode based on a converter parameter. This parameter is
/// of type Visibility, and specifies what visibility value to return when the boolean
/// value is true.
/// </summary>
private static Visibility GetVisibilityMode(object parameter)
{
// Default to Visible
Visibility mode = Visibility.Visible;
// If a parameter is specified, then we'll try to understand it as a Visibility value
if (parameter != null)
{
// If it's already a Visibility value, then just use it
if (parameter is Visibility)
{
mode = (Visibility)parameter;
}
else
{
// Let's try to parse the parameter as a Visibility value, throwing an exception when the parsing fails
try
{
mode = (Visibility)Enum.Parse(typeof(Visibility), parameter.ToString(), true);
}
catch (FormatException e)
{
throw new FormatException("Invalid Visibility specified as the ConverterParameter. Use Visible or Collapsed.", e);
}
}
}
// Return the detected mode
return mode;
}
/// <summary>
/// Determine whether or not visibility is inverted based on a converter parameter.
/// When the parameter is specified as Collapsed, that means that when the boolean value
/// is true, we should return Collapsed, which is inverted.
/// </summary>
private static bool IsVisibilityInverted(object parameter)
{
return (GetVisibilityMode(parameter) == Visibility.Collapsed);
}
/// <summary>
/// Support 2-way databinding of the VisibilityConverter, converting Visibility to a boolean
/// </summary>
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
bool isVisible = ((Visibility)value == Visibility.Visible);
// If visibility is inverted by the converter parameter, then invert our value
if (IsVisibilityInverted(parameter))
isVisible = !isVisible;
return isVisible;
}
}
}

73
App.config Normal file
View File

@ -0,0 +1,73 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<section name="GARbro.GUI.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false"/>
</sectionGroup>
</configSections>
<system.diagnostics>
<trace autoflush="true">
<listeners>
<add type="System.Diagnostics.TextWriterTraceListener" name="TextWriter" initializeData="trace.log"/>
</listeners>
</trace>
</system.diagnostics>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.1"/>
</startup>
<userSettings>
<GARbro.GUI.Properties.Settings>
<setting name="UpgradeRequired" serializeAs="String">
<value>True</value>
</setting>
<setting name="winTop" serializeAs="String">
<value>NaN</value>
</setting>
<setting name="winLeft" serializeAs="String">
<value>NaN</value>
</setting>
<setting name="winWidth" serializeAs="String">
<value>1024</value>
</setting>
<setting name="winHeight" serializeAs="String">
<value>560</value>
</setting>
<setting name="winState" serializeAs="String">
<value>Normal</value>
</setting>
<setting name="lvNameColumnWidth" serializeAs="String">
<value>265</value>
</setting>
<setting name="lvTypeColumnWidth" serializeAs="String">
<value>75</value>
</setting>
<setting name="lvSizeColumnWidth" serializeAs="String">
<value>75</value>
</setting>
<setting name="lvSortColumn" serializeAs="String">
<value>Name</value>
</setting>
<setting name="lvSortDirection" serializeAs="String">
<value>Ascending</value>
</setting>
<setting name="lvPanelWidth" serializeAs="String">
<value>448</value>
</setting>
<setting name="appExtractImages" serializeAs="String">
<value>True</value>
</setting>
<setting name="appExtractText" serializeAs="String">
<value>True</value>
</setting>
<setting name="appImageFormat" serializeAs="String">
<value />
</setting>
<setting name="appTextEncoding" serializeAs="String">
<value>UTF-8</value>
</setting>
<setting name="appLastDirectory" serializeAs="String">
<value />
</setting>
</GARbro.GUI.Properties.Settings>
</userSettings>
</configuration>

9
App.xaml Normal file
View File

@ -0,0 +1,9 @@
<Application x:Class="GARbro.GUI.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml" Startup="ApplicationStartup"
ShutdownMode="OnMainWindowClose" Exit="ApplicationExit">
<Application.Resources>
<BitmapImage x:Key="IconSearch" UriSource="pack://application:,,,/Images/search4files.ico" />
</Application.Resources>
</Application>

174
App.xaml.cs Normal file
View File

@ -0,0 +1,174 @@
// Game Resource Browser
//
// Copyright (C) 2014 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.IO;
using System.Configuration;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Threading;
using System.Reflection;
using System.Diagnostics;
using GARbro.GUI.Strings;
using GARbro.GUI.Properties;
using GameRes;
namespace GARbro.GUI
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
const StringComparison StringIgnoreCase = StringComparison.OrdinalIgnoreCase;
public static string Name { get { return "GARbro"; } }
public string InitPath { get; private set; }
public string CurrentPath { get; private set; }
public ArcFile CurrentArchive { get; private set; }
void ApplicationStartup (object sender, StartupEventArgs e)
{
Trace.WriteLine ("ApplicationStartup --------------------------------", "GARbro.GUI.App");
if (0 != e.Args.Length)
{
InitPath = Path.GetFullPath (e.Args[0]);
}
else if (!string.IsNullOrEmpty (Settings.Default.appLastDirectory))
{
try
{
string last_dir = Settings.Default.appLastDirectory;
Directory.SetCurrentDirectory (last_dir);
InitPath = last_dir;
}
catch { }
}
if (string.IsNullOrEmpty (InitPath))
InitPath = Directory.GetCurrentDirectory();
CurrentPath = "";
}
void ApplicationExit (object sender, ExitEventArgs e)
{
Settings.Default.appLastDirectory = Directory.GetCurrentDirectory();
Settings.Default.Save();
}
public ICollection<Entry> GetDirectoryList (string path)
{
var info = new DirectoryInfo (path);
var list = new List<Entry>();
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.Hidden | FileAttributes.System)))
continue;
var entry = FormatCatalog.Instance.CreateEntry (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);
/// <summary>
/// Processes all UI messages currently in the message queue.
/// </summary>
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))
{ }
}
}

284
ArcFormats/ArcAMI.cs Normal file
View File

@ -0,0 +1,284 @@
//! \file ArcAMI.cs
//! \date Thu Jul 03 09:40:40 2014
//! \brief Muv-Luv Amaterasu Translation archive.
//
using System;
using System.IO;
using System.Text;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using ZLibNet;
namespace GameRes.Formats
{
public class AmiEntry : PackedEntry
{
private Lazy<Tuple<string,string>> m_item;
public override string Name
{
get { return m_item.Value.Item1; }
set { m_item = new Lazy<Tuple<string, string>>(() => new Tuple<string, string>(value, Type)); }
}
public override string Type
{
get { return m_item.Value.Item2; }
set { m_item = new Lazy<Tuple<string, string>>(() => new Tuple<string, string>(Name, value)); }
}
public AmiEntry (Func<Tuple<string, string>> factory)
{
m_item = new Lazy<Tuple<string, string>> (factory);
}
}
[Export(typeof(ArchiveFormat))]
public class AmiOpener : ArchiveFormat
{
public override string Tag { get { return "AMI"; } }
public override string Description { get { return "Amaterasu Translations Muv-Luv archive"; } }
public override uint Signature { get { return 0x00494d41; } }
public AmiOpener ()
{
Extensions = new string[] { "ami", "amr" };
}
public override ArcFile TryOpen (ArcView file)
{
int count = file.View.ReadInt32 (4);
if (count <= 0)
return null;
uint base_offset = file.View.ReadUInt32 (8);
long max_offset = file.MaxOffset;
if (base_offset >= max_offset)
return null;
uint cur_offset = 16;
var dir = new List<Entry> (count);
for (int i = 0; i < count; ++i)
{
if (cur_offset+16 > base_offset)
return null;
uint id = file.View.ReadUInt32 (cur_offset);
uint offset = file.View.ReadUInt32 (cur_offset+4);
uint size = file.View.ReadUInt32 (cur_offset+8);
uint packed_size = file.View.ReadUInt32 (cur_offset+12);
var entry = new AmiEntry (() => {
uint signature = file.View.ReadUInt32 (offset);
string ext, type;
if (0x00524353 == signature) {
ext = "scr"; type = "script";
} else if (0 != packed_size) {
ext = "grp"; type = "image";
} else {
ext = "dat"; type = "";
}
string name = string.Format ("{0:x8}.{1}", id, ext);
return new Tuple<string,string> (name, type);
});
entry.Offset = offset;
entry.UnpackedSize = size;
entry.IsPacked = 0 != packed_size;
entry.Size = entry.IsPacked ? packed_size : size;
if (!entry.CheckPlacement (max_offset))
return null;
dir.Add (entry);
cur_offset += 16;
}
return new ArcFile (file, this, dir);
}
public override Stream OpenEntry (ArcFile arc, Entry entry)
{
var input = arc.File.CreateStream (entry.Offset, entry.Size);
var packed_entry = entry as AmiEntry;
if (null == packed_entry || !packed_entry.IsPacked)
return input;
else
return new ZLibStream (input, CompressionMode.Decompress);
}
}
[Export(typeof(ImageFormat))]
public class GrpFormat : ImageFormat
{
public override string Tag { get { return "GRP"; } }
public override string Description { get { return "âge proprietary image format"; } }
public override uint Signature { get { return 0x00505247; } }
public override ImageMetaData ReadMetaData (Stream stream)
{
using (var file = new BinaryReader (stream, Encoding.ASCII, true))
{
if (file.ReadUInt32() != Signature)
return null;
var meta = new ImageMetaData();
meta.OffsetX = file.ReadInt16();
meta.OffsetY = file.ReadInt16();
meta.Width = file.ReadUInt16();
meta.Height = file.ReadUInt16();
meta.BPP = 32;
stream.Position = 0;
return meta;
}
}
public override ImageData Read (Stream file, ImageMetaData info)
{
int width = (int)info.Width;
int height = (int)info.Height;
int stride = width*4;
byte[] pixels = new byte[stride*height];
file.Position = 12;
for (int row = height-1; row >= 0; --row)
{
if (stride != file.Read (pixels, row*stride, stride))
throw new InvalidFormatException();
}
var bitmap = BitmapSource.Create (width, height, 96, 96,
PixelFormats.Bgra32, null, pixels, stride);
bitmap.Freeze();
return new ImageData (bitmap, info);
}
public override void Write (Stream stream, ImageData image)
{
using (var file = new BinaryWriter (stream, Encoding.ASCII, true))
{
file.Write (Signature);
file.Write ((short)image.OffsetX);
file.Write ((short)image.OffsetY);
file.Write ((ushort)image.Width);
file.Write ((ushort)image.Height);
var bitmap = image.Bitmap;
if (bitmap.Format != PixelFormats.Bgra32)
{
var converted_bitmap = new FormatConvertedBitmap();
converted_bitmap.BeginInit();
converted_bitmap.Source = image.Bitmap;
converted_bitmap.DestinationFormat = PixelFormats.Bgra32;
converted_bitmap.EndInit();
bitmap = converted_bitmap;
}
int stride = (int)image.Width * 4;
byte[] row_data = new byte[stride];
Int32Rect rect = new Int32Rect (0, (int)image.Height, (int)image.Width, 1);
for (uint row = 0; row < image.Height; ++row)
{
--rect.Y;
bitmap.CopyPixels (rect, row_data, stride, 0);
file.Write (row_data);
}
}
}
}
public class AmiScriptData : ScriptData
{
public uint Id;
public uint Type;
}
[Export(typeof(ScriptFormat))]
public class ScrFormat : ScriptFormat
{
public override string Tag { get { return "SCR"; } }
public override string Description { get { return "Amaterasu Translations Muv-Luv script file"; } }
public override uint Signature { get { return 0x00524353; } }
public override ScriptData Read (string name, Stream stream)
{
if (Signature != FormatCatalog.ReadSignature (stream))
return null;
uint script_id = Convert.ToUInt32 (name, 16);
uint max_offset = (uint)Math.Min (stream.Length, 0xffffffff);
using (var file = new BinaryReader (stream, Encodings.cp932, true))
{
uint script_type = file.ReadUInt32();
var script = new AmiScriptData {
Id = script_id,
Type = script_type
};
uint count = file.ReadUInt32();
for (uint i = 0; i < count; ++i)
{
uint offset = file.ReadUInt32();
if (offset >= max_offset)
throw new InvalidFormatException ("Invalid offset in script data file");
int size = file.ReadInt32();
uint id = file.ReadUInt32();
var header_pos = file.BaseStream.Position;
file.BaseStream.Position = offset;
byte[] line = file.ReadBytes (size);
if (line.Length != size)
throw new InvalidFormatException ("Premature end of file");
string text = Encodings.cp932.GetString (line);
script.TextLines.Add (new ScriptLine { Id = id, Text = text });
file.BaseStream.Position = header_pos;
}
return script;
}
}
public string GetName (ScriptData script_data)
{
var script = script_data as AmiScriptData;
if (null != script)
return script.Id.ToString ("x8");
else
return null;
}
struct IndexEntry
{
public uint offset, size, id;
}
public override void Write (Stream stream, ScriptData script_data)
{
var script = script_data as AmiScriptData;
if (null == script)
throw new ArgumentException ("Illegal ScriptData", "script_data");
using (var file = new BinaryWriter (stream, Encodings.cp932, true))
{
file.Write (Signature);
file.Write (script.Type);
uint count = (uint)script.TextLines.Count;
file.Write (count);
var index_pos = file.BaseStream.Position;
file.Seek ((int)count*12, SeekOrigin.Current);
var index = new IndexEntry[count];
int i = 0;
foreach (var line in script.TextLines)
{
var text = Encodings.cp932.GetBytes (line.Text);
index[i].offset = (uint)file.BaseStream.Position;
index[i].size = (uint)text.Length;
index[i].id = line.Id;
file.Write (text);
file.Write ((byte)0);
++i;
}
var end_pos = file.BaseStream.Position;
file.BaseStream.Position = index_pos;
foreach (var entry in index)
{
file.Write (entry.offset);
file.Write (entry.size);
file.Write (entry.id);
}
file.BaseStream.Position = end_pos;
}
}
}
}

View File

@ -0,0 +1,149 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{A8865685-27CC-427B-AC38-E48D2AD05DF4}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>GameRes.Formats</RootNamespace>
<AssemblyName>ArcFormats</AssemblyName>
<TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>..\bin\Release\</OutputPath>
<DefineConstants>
</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
<Reference Include="System" />
<Reference Include="System.ComponentModel.Composition" />
<Reference Include="System.Core" />
<Reference Include="System.Xaml" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
<Reference Include="WindowsBase" />
<Reference Include="zlibnet, Version=1.3.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\zlibnet\zlibnet.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="ArcAMI.cs" />
<Compile Include="ArcINT.cs" />
<Compile Include="ArcNPA.cs" />
<Compile Include="ArcXFL.cs" />
<Compile Include="ArcXP3.cs" />
<Compile Include="ArcYPF.cs" />
<Compile Include="Blowfish.cs" />
<Compile Include="ImageHG3.cs" />
<Compile Include="ImageTLG.cs" />
<Compile Include="ImageWCG.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
<DependentUpon>Settings.settings</DependentUpon>
</Compile>
<Compile Include="Settings.cs" />
<Compile Include="Strings\arcStrings.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>arcStrings.resx</DependentUpon>
</Compile>
<Compile Include="WidgetINT.xaml.cs">
<DependentUpon>WidgetINT.xaml</DependentUpon>
</Compile>
<Compile Include="WidgetNPA.xaml.cs">
<DependentUpon>WidgetNPA.xaml</DependentUpon>
</Compile>
<Compile Include="WidgetXP3.xaml.cs">
<DependentUpon>WidgetXP3.xaml</DependentUpon>
</Compile>
<Compile Include="WidgetYPF.xaml.cs">
<DependentUpon>WidgetYPF.xaml</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\GameRes\GameRes.csproj">
<Project>{453c087f-e416-4ae9-8c03-d8760da0574b}</Project>
<Name>GameRes</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Content Include="..\zlib\zlib32.dll">
<Link>zlib32.dll</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="..\zlib\zlib64.dll">
<Link>zlib64.dll</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="packages.config" />
<None Include="Properties\Settings.settings">
<Generator>PublicSettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
</ItemGroup>
<ItemGroup>
<Page Include="WidgetINT.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="WidgetNPA.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="WidgetXP3.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="WidgetYPF.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Strings\arcStrings.resx">
<Generator>PublicResXFileCodeGenerator</Generator>
<LastGenOutput>arcStrings.Designer.cs</LastGenOutput>
</EmbeddedResource>
<EmbeddedResource Include="Strings\arcStrings.ru-RU.resx" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

288
ArcFormats/ArcINT.cs Normal file
View File

@ -0,0 +1,288 @@
//! \file ArcINT.cs
//! \date Fri Jul 11 09:32:36 2014
//! \brief Frontwing games archive.
//
using System;
using System.IO;
using System.Linq;
using System.Text;
using System.ComponentModel.Composition;
using System.Collections.Generic;
using System.Diagnostics;
using Simias.Encryption;
using System.Runtime.InteropServices;
using GameRes.Formats.Strings;
using GameRes.Formats.Properties;
namespace GameRes.Formats
{
public class FrontwingArchive : ArcFile
{
public readonly Blowfish Encryption;
public FrontwingArchive (ArcView arc, ArchiveFormat impl, ICollection<Entry> dir, Blowfish cipher)
: base (arc, impl, dir)
{
Encryption = cipher;
}
}
public class IntEncryptionInfo
{
public uint? Key { get; set; }
public string Scheme { get; set; }
public string Password { get; set; }
public IntEncryptionInfo () { }
}
[Export(typeof(ArchiveFormat))]
public class IntOpener : ArchiveFormat
{
public override string Tag { get { return "INT"; } }
public override string Description { get { return "FrontWing game resource archive"; } }
public override uint Signature { get { return 0x0046494b; } }
public override ArcFile TryOpen (ArcView file)
{
uint entry_count = file.View.ReadUInt32 (4);
if (0 == entry_count || 0 != ((entry_count - 1) >> 0x14))
{
Trace.WriteLine (string.Format ("Invalid entry count ({0})", entry_count));
return null;
}
if (file.View.AsciiEqual (8, "__key__.dat\x00"))
{
uint? key = QueryEncryptionInfo();
if (null == key)
throw new UnknownEncryptionScheme();
return OpenEncrypted (file, entry_count, key.Value);
}
long current_offset = 8;
var dir = new List<Entry>();
for (uint i = 0; i < entry_count; ++i)
{
string name = file.View.ReadString (current_offset, 0x40);
var entry = FormatCatalog.Instance.CreateEntry (name);
entry.Offset = file.View.ReadUInt32 (current_offset+0x40);
entry.Size = file.View.ReadUInt32 (current_offset+0x44);
if (!entry.CheckPlacement (file.MaxOffset))
return null;
dir.Add (entry);
current_offset += 0x48;
}
return new ArcFile (file, this, dir);
}
private ArcFile OpenEncrypted (ArcView file, uint entry_count, uint main_key)
{
if (1 == entry_count)
return null; // empty archive
long current_offset = 8;
var twister = new Twister();
// [@@L1] = 32-bit key
// [@@L1+4] = 0 if key is available, -1 otherwise
uint key_data = file.View.ReadUInt32 (current_offset+0x44);
uint twist_key = twister.Twist (key_data);
// [@@L0] = 32-bit twist key
byte[] blowfish_key = BitConverter.GetBytes (twist_key);
if (!BitConverter.IsLittleEndian)
Array.Reverse (blowfish_key);
var blowfish = new Blowfish (blowfish_key);
var dir = new List<Entry>();
byte[] name_info = new byte[0x40];
for (uint i = 1; i < entry_count; ++i)
{
current_offset += 0x48;
file.View.Read (current_offset, name_info, 0, 0x40);
uint eax = file.View.ReadUInt32 (current_offset+0x40);
uint edx = file.View.ReadUInt32 (current_offset+0x44);
eax += i;
blowfish.Decipher (ref eax, ref edx);
uint key = twister.Twist (main_key + i);
string name = DecipherName (name_info, key);
var entry = FormatCatalog.Instance.CreateEntry (name);
entry.Offset = eax;
entry.Size = edx;
if (!entry.CheckPlacement (file.MaxOffset))
return null;
dir.Add (entry);
}
return new FrontwingArchive (file, this, dir, blowfish);
}
private Stream OpenEncryptedEntry (FrontwingArchive arc, Entry entry)
{
using (var view = arc.File.CreateViewAccessor (entry.Offset, entry.Size))
{
byte[] data = new byte[entry.Size];
// below is supposedly faster version of
//arc.File.View.Read (entry.Offset, data, 0, entry.Size);
unsafe
{
byte* ptr = view.GetPointer (entry.Offset);
try {
Marshal.Copy (new IntPtr(ptr), data, 0, data.Length);
} finally {
view.SafeMemoryMappedViewHandle.ReleasePointer();
}
}
arc.Encryption.Decipher (data, data.Length/8*8);
return new MemoryStream (data, false);
}
}
public override Stream OpenEntry (ArcFile arc, Entry entry)
{
if (arc is FrontwingArchive)
return OpenEncryptedEntry (arc as FrontwingArchive, entry);
else
return base.OpenEntry (arc, entry);
}
public string DecipherName (byte[] name, uint key)
{
key += (key >> 8) + (key >> 16) + (key >> 24);
key &= 0xff;
key %= 0x34;
int count = 0;
for (int i = 0; i < name.Length; ++i)
{
byte al = name[i];
if (0 == al)
break;
byte bl = (byte)key;
++count;
uint edx = al;
al |= 0x20;
al -= 0x61;
if (al < 0x1a)
{
if (0 != (edx & 0x20))
al += 0x1a;
al = (byte)~al;
al += 0x34;
if (al >= bl)
al -= bl;
else
al = (byte)(al - bl + 0x34);
if (al >= 0x1a)
al += 6;
al += 0x41;
name[i] = al;
}
++key;
if (0x34 == key)
key = 0;
}
return Encodings.cp932.GetString (name, 0, count);
}
class Twister
{
const uint TwisterLength = 0x270;
uint[] m_twister = new uint[TwisterLength];
uint m_twister_pos = 0;
public uint Twist (uint key)
{
Init (key);
return Next();
}
public void Init (uint key)
{
uint edx = key;
for (int i = 0; i < TwisterLength; ++i)
{
uint ecx = edx * 0x10dcd + 1;
m_twister[i] = (edx & 0xffff0000) | (ecx >> 16);
edx *= 0x1C587629;
edx += 0x10dce;
}
m_twister_pos = 0;
}
public uint Next ()
{
uint ecx = m_twister[m_twister_pos];
uint edx = m_twister_pos + 1;
if (TwisterLength == edx)
edx = 0;
uint edi = m_twister[edx];
edi = ((edi ^ ecx) & 0x7FFFFFFF) ^ ecx;
bool carry = 0 != (edi & 1);
edi >>= 1;
if (carry)
edi ^= 0x9908B0DF;
ecx = m_twister_pos + 0x18d;
if (ecx >= TwisterLength)
ecx -= TwisterLength;
edi ^= m_twister[ecx];
m_twister[m_twister_pos] = edi;
m_twister_pos = edx;
uint eax = edi ^ (edi >> 11);
eax = ((eax & 0xFF3A58AD) << 7) ^ eax;
eax = ((eax & 0xFFFFDF8C) << 15) ^ eax;
eax = (eax >> 18) ^ eax;
return eax;
}
}
public static uint EncodePassPhrase (string password)
{
byte[] pass_bytes = Encodings.cp932.GetBytes (password);
uint key = 0xffffffff;
foreach (var c in pass_bytes)
{
uint val = (uint)c << 24;
key ^= val;
for (int i = 0; i < 8; ++i)
{
bool carry = 0 != (key & 0x80000000);
key <<= 1;
if (carry)
key ^= 0x4C11DB7;
}
key = ~key;
}
return key;
}
public struct KeyData
{
public uint Key;
public string Passphrase;
}
public static readonly Dictionary<string, KeyData> KnownSchemes = new Dictionary<string, KeyData> {
{ "Grisaia no Kajitsu", new KeyData { Key=0x1DAD9120, Passphrase="FW-6JD55162" }},
{ "Shukufuku no Campanella", new KeyData { Key=0x4260E643, Passphrase="CAMPANELLA" }},
{ "Makai Tenshi Djibril -Episode 4-", new KeyData { Key=0xA5A166AA, Passphrase="FW_MAKAI-TENSHI_DJIBRIL4" }},
{ "Sengoku Tenshi Djibril (trial)", new KeyData { Key=0xef870610, Passphrase="FW-8O9B6WDS" }},
};
IntEncryptionInfo m_info = Settings.Default.INTEncryption ?? new IntEncryptionInfo();
uint? QueryEncryptionInfo ()
{
var widget = new GUI.WidgetINT (m_info);
var args = new ParametersRequestEventArgs
{
Notice = arcStrings.INTNotice,
InputWidget = widget,
};
FormatCatalog.Instance.InvokeParametersRequest (this, args);
if (!args.InputResult)
throw new OperationCanceledException();
Settings.Default.INTEncryption = widget.Info;
return widget.GetKey();
}
}
}

376
ArcFormats/ArcNPA.cs Normal file
View File

@ -0,0 +1,376 @@
//! \file ArcNPA.cs
//! \date Fri Jul 18 04:07:42 2014
//! \brief NPA archive format implementation.
//
using System;
using System.IO;
using System.ComponentModel.Composition;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using ZLibNet;
using GameRes.Formats.Strings;
using GameRes.Formats.Properties;
namespace GameRes.Formats
{
public class NpaEntry : PackedEntry
{
public byte[] RawName;
}
public class NpaArchive : ArcFile
{
public NpaTitleId GameId { get; private set; }
public int Key { get; private set; }
public byte[] KeyTable { get { return m_key_table.Value; } }
private Lazy<byte[]> m_key_table;
public NpaArchive (ArcView arc, ArchiveFormat impl, ICollection<Entry> dir,
NpaTitleId game_id, int key)
: base (arc, impl, dir)
{
GameId = game_id;
Key = key;
m_key_table = new Lazy<byte[]> (() => NpaOpener.GenerateKeyTable (game_id));
}
}
public enum NpaTitleId
{
CHAOSHEAD = 0, CHAOSHEADTR1, CHAOSHEADTR2, MURAMASATR, MURAMASA, SUMAGA, DJANGO, DJANGOTR,
LAMENTO, LAMENTOTR, SWEETPOOL, SUMAGASP, DEMONBANE, MURAMASAAD, AXANAEL, KIKOKUGAI, SONICOMITR2,
SUMAGA3P, SONICOMI, LOSTX, LOSTXTRAILER, DRAMATICALMURDER, TOTONO, PHENOMENO, NEKODA,
NotEncrypted
}
[Export(typeof(ArchiveFormat))]
public class NpaOpener : ArchiveFormat
{
public override string Tag { get { return "NPA"; } }
public override string Description { get { return "Nitro+ resource archive"; } }
public override uint Signature { get { return 0x0141504e; } } // NPA\x01
/// <summary>Known encryption schemes.</summary>
public static readonly string[] KnownSchemes = new string[] {
"Chaos;Head", "Chaos;Head Trial 1", "Chaos;Head Trial 2", "Muramasa Trial", "Muramasa",
"Sumaga", "Zoku Satsuriku no Django", "Zoku Satsuriku no Django Trial", "Lamento",
"Lamento Trial", "Sweet Pool", "Sumaga Special", "Demonbane", "MuramasaAD", "Axanael",
"Kikokugai", "Sonicomi Trial 2", "Sumaga 3% Trial", "Sonicomi Version 1.0",
"Guilty Crown Lost Xmas", "Guilty Crown Lost Xmas Trailer", "DRAMAtical Murder",
"Kimi to Kanojo to Kanojo no Koi", "Phenomeno", "Nekoda -Nyanda-",
arcStrings.ArcNoEncryption,
};
/// <summary>Game id of the last opened archive.</summary>
NpaTitleId m_game_id = Settings.Default.NPAScheme;
public override ArcFile TryOpen (ArcView file)
{
int key1 = file.View.ReadInt32 (7);
int key2 = file.View.ReadInt32 (11);
bool compressed = 0 != file.View.ReadByte (15);
bool encrypted = 0 != file.View.ReadByte (16);
int total_count = file.View.ReadInt32 (17);
int folder_count = file.View.ReadInt32 (21);
int file_count = file.View.ReadInt32 (25);
if (total_count < folder_count + file_count)
return null;
uint dir_size = file.View.ReadUInt32 (37);
if (dir_size >= file.MaxOffset)
return null;
var game_id = NpaTitleId.NotEncrypted;
if (encrypted)
game_id = QueryGameEncryption();
int key;
if (encrypted && (game_id == NpaTitleId.LAMENTO || game_id == NpaTitleId.LAMENTOTR))
key = key1 + key2;
else
key = key1 * key2;
long cur_offset = 41;
var dir = new List<Entry> (file_count);
for (int i = 0; i < total_count; ++i)
{
int name_size = file.View.ReadInt32 (cur_offset);
int type = file.View.ReadByte (cur_offset+4+name_size);
if (1 != type)
{
var raw_name = new byte[name_size];
file.View.Read (cur_offset+4, raw_name, 0, (uint)name_size);
for (int x = 0; x < name_size; ++x)
raw_name[x] += DecryptName (x, i, key);
var info_offset = cur_offset + 5 + name_size;
uint id = file.View.ReadUInt32 (info_offset);
uint offset = file.View.ReadUInt32 (info_offset+4);
uint size = file.View.ReadUInt32 (info_offset+8);
uint unpacked_size = file.View.ReadUInt32 (info_offset+12);
var entry = new NpaEntry {
Name = Encodings.cp932.GetString (raw_name),
Offset = dir_size+offset+41,
Size = size,
UnpackedSize = unpacked_size,
IsPacked = compressed,
RawName = raw_name,
};
entry.Type = FormatCatalog.Instance.GetTypeFromName (entry.Name);
dir.Add (entry);
}
cur_offset += 4 + name_size + 17;
}
if (game_id != NpaTitleId.NotEncrypted)
return new NpaArchive (file, this, dir, game_id, key);
else
return new ArcFile (file, this, dir);
}
public override Stream OpenEntry (ArcFile arc, Entry entry)
{
if (arc is NpaArchive && entry is NpaEntry)
return OpenEncryptedEntry (arc as NpaArchive, entry as NpaEntry);
var input = arc.File.CreateStream (entry.Offset, entry.Size);
return UnpackEntry (input, entry);
}
private Stream UnpackEntry (Stream input, Entry entry)
{
if (entry.Type != "image")
{
var npa_entry = entry as PackedEntry;
if (null != npa_entry && npa_entry.IsPacked)
return new ZLibStream (input, CompressionMode.Decompress);
}
return input;
}
private Stream OpenEncryptedEntry (NpaArchive arc, NpaEntry entry)
{
int key = GetKeyFromEntry (entry, arc.GameId, arc.Key);
int encrypted_length = 0x1000;
if (arc.GameId != NpaTitleId.LAMENTO && arc.GameId != NpaTitleId.LAMENTOTR)
encrypted_length += entry.RawName.Length;
using (var view = arc.File.CreateViewAccessor (entry.Offset, entry.Size))
{
byte[] buffer = new byte[entry.Size];
unsafe
{
byte* src = view.GetPointer (entry.Offset);
try
{
int x;
for (x = 0; x < entry.Size && x < encrypted_length; x++)
{
if (arc.GameId == NpaTitleId.LAMENTO || arc.GameId == NpaTitleId.LAMENTOTR)
{
buffer[x] = (byte)(arc.KeyTable[src[x]] - key);
}
else if (arc.GameId == NpaTitleId.TOTONO)
{
byte r = src[x];
r = arc.KeyTable[r];
r = arc.KeyTable[r];
r = arc.KeyTable[r];
r = (byte)~r;
buffer[x] = (byte)((sbyte)r - key - x);
}
else
{
buffer[x] = (byte)(arc.KeyTable[src[x]] - key - x);
}
}
if (x != entry.Size)
Marshal.Copy ((IntPtr)(src+x), buffer, x, (int)(entry.Size-x));
} finally {
view.SafeMemoryMappedViewHandle.ReleasePointer();
}
}
return UnpackEntry (new MemoryStream (buffer, false), entry);
}
}
byte DecryptName (int index, int curfile, int arc_key)
{
int key = 0xFC*index;
key -= arc_key >> 0x18;
key -= arc_key >> 0x10;
key -= arc_key >> 0x08;
key -= arc_key & 0xff;
key -= curfile >> 0x18;
key -= curfile >> 0x10;
key -= curfile >> 0x08;
key -= curfile;
return (byte)(key & 0xff);
}
byte GetKeyFromEntry (NpaEntry entry, NpaTitleId game_id, int key2)
{
int key1;
switch (game_id)
{
case NpaTitleId.AXANAEL:
case NpaTitleId.KIKOKUGAI:
case NpaTitleId.SONICOMITR2:
case NpaTitleId.SONICOMI:
case NpaTitleId.LOSTX:
case NpaTitleId.DRAMATICALMURDER:
key1 = 0x20101118;
break;
case NpaTitleId.TOTONO:
key1 = 0x12345678;
break;
default:
key1 = unchecked((int)0x87654321);
break;
}
var name = entry.RawName;
int i;
for (i = 0; i < name.Length; ++i)
key1 -= name[i];
int key = key1 * i;
if (game_id != NpaTitleId.LAMENTO && game_id != NpaTitleId.LAMENTOTR) // if the game is not Lamento
{
key += key2;
key *= (int)entry.UnpackedSize;
}
return (byte)(key & 0xff);
}
public static byte[] GenerateKeyTable (NpaTitleId title_id)
{
if ((int)title_id >= OrderTable.Length)
throw new ArgumentOutOfRangeException ("title_id", "Invalid title id specified");
byte[] order = OrderTable[(int)title_id];
var table = new byte[256];
for (int i = 0; i < 256; ++i)
{
int edx = i << 4;
int dl = (edx + order[i & 0x0f]) & 0xff;
int dh = (edx + (order[i>>4] << 8)) & 0xff00;
edx = (dh | dl) >> 4;
var eax = BaseTable[i];
table[eax] = (byte)(edx & 0xff);
}
for (int i = 16; i+1 < order.Length; i+=2)
{
int ecx = order[i];
int edx = order[i+1];
byte tmp = table[ecx];
table[ecx] = table[edx];
table[edx] = tmp;
}
return table;
}
NpaTitleId QueryGameEncryption ()
{
var widget = new GUI.WidgetNPA (KnownSchemes[(int)m_game_id]);
var args = new ParametersRequestEventArgs
{
Notice = arcStrings.ArcEncryptedNotice,
InputWidget = widget,
};
FormatCatalog.Instance.InvokeParametersRequest (this, args);
if (!args.InputResult)
throw new OperationCanceledException();
NpaTitleId scheme = GetTitleId (widget.GetScheme());
Settings.Default.NPAScheme = scheme;
return scheme;
}
public static NpaTitleId GetTitleId (string title)
{
var index = Array.IndexOf (KnownSchemes, title);
if (index != -1)
return (NpaTitleId)index;
else
return NpaTitleId.NotEncrypted;
}
static readonly byte[] BaseTable = {
0x6F,0x05,0x6A,0xBF,0xA1,0xC7,0x8E,0xFB,0xD4,0x2F,0x80,0x58,0x4A,0x17,0x3B,0xB1,
0x89,0xEC,0xA0,0x9F,0xD3,0xFC,0xC2,0x04,0x68,0x03,0xF3,0x25,0xBE,0x24,0xF1,0xBD,
0xB8,0x41,0xC9,0x27,0x0E,0xA3,0xD8,0x7F,0x5B,0x8F,0x16,0x49,0xAA,0xB2,0x18,0xA7,
0x33,0xE4,0xDB,0x48,0xCA,0xDE,0xAE,0xCD,0x13,0x1F,0x15,0x2E,0x39,0xF5,0x1E,0xDD,
0x0F,0x88,0x4C,0x98,0x36,0xB4,0x3F,0x09,0x83,0xFD,0x32,0xBA,0x14,0x30,0x7A,0x63,
0xB9,0x56,0x95,0x61,0xCC,0x8B,0xEF,0xDA,0xE5,0x2C,0xDC,0x12,0x1A,0x67,0x23,0x50,
0xD1,0xC3,0x7E,0x6D,0xB6,0x90,0x3C,0xB3,0x0B,0xE2,0x91,0x70,0xA8,0xDF,0x44,0xC4,
0xF4,0x01,0x5C,0x10,0x06,0xE7,0x54,0x40,0x43,0x72,0x38,0xBC,0xE3,0x07,0xFA,0x34,
0x02,0xA4,0xF7,0x74,0xA9,0x4D,0x42,0xA5,0x85,0x35,0x79,0xD2,0x76,0x97,0x45,0x4F,
0x08,0x5A,0xB0,0xEE,0x51,0x73,0x69,0x9E,0x94,0x47,0x77,0x29,0xD9,0x64,0x11,0xEB,
0x37,0xAC,0x20,0x62,0x9A,0x6B,0x9C,0x75,0x22,0x87,0xAB,0x78,0x53,0xC8,0x5D,0xAD,
0x2A,0xF2,0xCB,0xB7,0x0D,0xED,0x86,0x55,0xFF,0x19,0x57,0xD7,0xD5,0x60,0xC6,0x3D,
0xEA,0xC1,0x6C,0xE1,0xC0,0x65,0x84,0xC5,0xE0,0x3E,0x7D,0x28,0x66,0xAF,0x1C,0x9B,
0xCF,0x81,0x4E,0x26,0x59,0x2B,0x5F,0x7B,0xE8,0x8D,0x52,0x7C,0xF8,0x82,0x0C,0xF9,
0x8C,0xE9,0xB5,0xE6,0x31,0x93,0x46,0x5E,0x1D,0x1B,0x4B,0x71,0xD6,0x92,0x3A,0xA6,
0x2D,0x00,0x9D,0xBB,0x6E,0xF0,0x99,0xCE,0x21,0x0A,0xD0,0xF6,0xFE,0xA2,0x8A,0x96,
};
static readonly byte[][] OrderTable = {
// CHAOSHEAD
new byte[] { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
// CHAOSHEADTR1
new byte[] { 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x1e,0x4e,0x66,0xb6 },
// CHAOSHEADTR2
new byte[] { 0x05,0x05,0x05,0x05,0x05,0x0b,0x0b,0x0b,0x0b,0x0b,0x00,0x00,0x00,0x00,0x00,0x00 },
// MURAMASATR
new byte[] { 0x3c,0xe0,0x2e,0x2f,0x20,0x2e,0x2f,0x20,0x8e,0x80,0x80,0xf2,0xf2,0xf2,0xfa,0xfc },
// MURAMASA
new byte[] { 0x35,0x70,0x2e,0x66,0x67,0x65,0x66,0x67,0x85,0x89,0x89,0x3b,0x3b,0x8b,0x81,0x85 },
// SUMAGA
new byte[] { 0x3c,0xe0,0x2e,0x2f,0x2f,0x2f,0x2f,0x20,0x8e,0x8f,0x8f,0xf2,0xf2,0xf2,0xfc,0xfc },
// DJANGO
new byte[] { 0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xee,0x1e,0x4e,0x66,0xb6 },
// DJANGOTR
new byte[] { 0xed,0xee,0xee,0xef,0xed,0xee,0xee,0xee,0xfe,0xde,0xee,0xef,0xed,0xee,0xfe,0xdf,0x1e,0x4e,0x66,0xb6 },
// LAMENTO
new byte[] { 0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xee,0x1e,0x4e,0x66,0xb6 },
// LAMENTOTR
new byte[] { 0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xee,0xee,0x1e,0x4e,0x66,0xb6 },
// SWEETPOOL
new byte[] { 0x38,0x9c,0x2a,0x8b,0x8b,0x8b,0x8b,0x8c,0x8a,0x8b,0x8b,0xae,0xae,0xae,0xa8,0xa8 },
// SUMAGASP
new byte[] { 0xab,0x6f,0x9d,0x9e,0x9f,0x9d,0x9e,0xaf,0x8d,0xff,0xff,0x71,0x71,0x71,0x79,0x7b },
// DEMONBANE
new byte[] { 0x96,0xb9,0x47,0x48,0x99,0x97,0x9c,0xaa,0x88,0xca,0xea,0x73,0x73,0x7b,0xc9,0xc6 },
// MURAMASAAD
new byte[] { 0x00,0x04,0x04,0x68,0x68,0x68,0x68,0x68,0x6f,0x6f,0x9f,0x96,0x96,0x96,0x96,0x9b },
// AXANAEL
new byte[] { 0x08,0x0c,0x0c,0xc0,0xf0,0xf0,0xf0,0xf0,0xf7,0xf7,0xf7,0xfe,0xfe,0xfe,0xfe,0xf3 },
// KIKOKUGAI
new byte[] { 0x0f,0x07,0x07,0x90,0xf7,0xf7,0xf7,0xf7,0xf2,0x47,0x47,0x49,0xc9,0xc9,0xc9,0xc3 },
// SONICOMITR2
new byte[] { 0x08,0x0a,0x0a,0x40,0xfa,0xfa,0x50,0x50,0x55,0xf7,0xf7,0xf9,0x29,0x2c,0x7c,0x73 },
// SUMAGA3P
new byte[] { 0x0f,0xef,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff },
// SONICOMI
new byte[] { 0x0e,0x0b,0x0e,0x77,0x2e,0x2e,0x80,0x86,0xb9,0x2e,0x2e,0x29,0x89,0x82,0xad,0xaa },
// LOSTX
new byte[] { 0x38,0xba,0x4b,0x5b,0x55,0xae,0xee,0xe0,0x67,0x48,0x08,0x0a,0x6a,0x3d,0x32,0x8d },
// LOSTXTRAILER
new byte[] { 0x34,0x7a,0xbb,0xcb,0x11,0x65,0xea,0x5c,0x27,0x0f,0xcf,0xc6,0x66,0x39,0x39,0xfd },
// DRAMATICALMURDER
new byte[] { 0x05,0x0d,0x0d,0x13,0xb5,0x3d,0x8d,0x2d,0x20,0xc7,0xc7,0xcf,0x1f,0xef,0xef,0x48 },
// TOTONO
new byte[] { 0x6e,0x60,0x90,0xac,0xb3,0xe3,0x83,0xd6,0xde,0x7a,0x7a,0x7f,0xef,0xbf,0xb2,0xd6 },
// PHENOMENO
new byte[] { 0x30,0x96,0xdb,0x2b,0x3d,0x81,0x02,0x74,0x47,0x2b,0xeb,0xee,0x6e,0x35,0x35,0x5d },
// NEKODA
new byte[] { 0xdc,0xdc,0xec,0xcd,0xdb,0xdc,0xdc,0xdc,0xdc,0xdc,0xdc,0xdc,0xdc,0xdc,0xdc,0xdc,0x1e,0x4e,0x66,0xb6 },
};
}
}

212
ArcFormats/ArcXFL.cs Normal file
View File

@ -0,0 +1,212 @@
//! \file ArcXFL.cs
//! \date Mon Jun 30 21:18:29 2014
//! \brief XFL resource format implementation.
//
using System;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Text;
using System.Collections.Generic;
using System.ComponentModel.Composition;
namespace GameRes.Formats
{
[Export(typeof(ArchiveFormat))]
public class XflOpener : ArchiveFormat
{
public override string Tag { get { return "XFL"; } }
public override string Description { get { return "Liar-soft game resource archive"; } }
public override uint Signature { get { return 0x0001424c; } }
public override ArcFile TryOpen (ArcView file)
{
uint dir_size = file.View.ReadUInt32 (4);
int count = file.View.ReadInt32 (8);
if (count <= 0)
return null;
long max_offset = file.MaxOffset;
uint base_offset = dir_size + 12;
if (dir_size >= max_offset || base_offset >= max_offset)
return null;
file.View.Reserve (0, base_offset);
long cur_offset = 12;
var dir = new List<Entry> (count);
for (int i = 0; i < count; ++i)
{
if (cur_offset+40 > base_offset)
return null;
string name = file.View.ReadString (cur_offset, 32);
var entry = FormatCatalog.Instance.CreateEntry (name);
entry.Offset = base_offset + file.View.ReadUInt32 (cur_offset+32);
entry.Size = file.View.ReadUInt32 (cur_offset+36);
if (!entry.CheckPlacement (max_offset))
return null;
dir.Add (entry);
cur_offset += 40;
}
return new ArcFile (file, this, dir);
}
}
public class LwgImageEntry : ImageEntry
{
public int PosX;
public int PosY;
public int BPP;
}
[Export(typeof(ArchiveFormat))]
public class LwgOpener : ArchiveFormat
{
public override string Tag { get { return "LWG"; } }
public override string Description { get { return "Liar-soft image archive"; } }
public override uint Signature { get { return 0x0001474c; } }
public override ArcFile TryOpen (ArcView file)
{
uint height = file.View.ReadUInt32 (4);
uint width = file.View.ReadUInt32 (8);
int count = file.View.ReadInt32 (12);
if (count <= 0)
return null;
uint dir_size = file.View.ReadUInt32 (20);
uint cur_offset = 24;
uint data_offset = cur_offset + dir_size;
uint data_size = file.View.ReadUInt32 (data_offset);
data_offset += 4;
var dir = new List<Entry> (count);
for (int i = 0; i < count; ++i)
{
var entry = new LwgImageEntry();
entry.PosX = file.View.ReadInt32 (cur_offset);
entry.PosY = file.View.ReadInt32 (cur_offset+4);
entry.BPP = file.View.ReadByte (cur_offset+8);
entry.Offset = data_offset + file.View.ReadUInt32 (cur_offset+9);
entry.Size = file.View.ReadUInt32 (cur_offset+13);
uint name_length = file.View.ReadByte (cur_offset+17);
string name = file.View.ReadString (cur_offset+18, name_length, Encoding.ASCII);
entry.Name = name + ".wcg";
cur_offset += 18+name_length;
if (cur_offset > dir_size+24)
return null;
if (entry.CheckPlacement (data_offset + data_size))
dir.Add (entry);
}
return new ArcFile (file, this, dir);
}
}
public class GscScriptData : ScriptData
{
public byte[] Header;
public byte[] Code;
public byte[] Footer;
}
//[Export(typeof(ScriptFormat))]
public class GscFormat : ScriptFormat
{
public override string Tag { get { return "GSC"; } }
public override string Description { get { return "Liar-soft proprietary script format"; } }
public override uint Signature { get { return 0; } }
public override ScriptData Read (string name, Stream stream)
{
using (var file = new BinaryReader (stream, Encodings.cp932, true))
{
uint signature = file.ReadUInt32();
if (signature != file.BaseStream.Length)
return null;
uint header_size = file.ReadUInt32();
if (header_size > 0x24 || header_size < 0x14)
return null;
uint code_size = file.ReadUInt32();
uint text_index_size = file.ReadUInt32();
uint text_size = file.ReadUInt32();
byte[] header_data = file.ReadBytes ((int)header_size-0x14);
byte[] code = file.ReadBytes ((int)code_size);
uint[] index = new uint[text_index_size/4];
for (int i = 0; i < index.Length; ++i)
{
index[i] = file.ReadUInt32();
if (index[i] >= text_size)
return null;
}
long text_offset = header_size + code_size + text_index_size;
var script = new GscScriptData();
script.Header = header_data;
script.Code = code;
for (int i = 0; i < index.Length; ++i)
{
file.BaseStream.Position = text_offset + index[i];
string text = StreamExtension.ReadCString (file.BaseStream);
script.TextLines.Add (new ScriptLine { Id = (uint)i, Text = text });
}
long footer_pos = text_offset + text_size;
file.BaseStream.Position = footer_pos;
script.Footer = new byte[file.BaseStream.Length - footer_pos];
file.BaseStream.Read (script.Footer, 0, script.Footer.Length);
return script;
}
}
public override void Write (Stream stream, ScriptData script_data)
{
var script = script_data as GscScriptData;
if (null == script)
throw new InvalidFormatException();
using (var file = new BinaryWriter (stream, Encodings.cp932, true))
{
long file_size_pos = file.BaseStream.Position;
file.Write ((int)0);
file.Write ((int)(script.Header.Length + 0x14));
file.Write ((int)script.Code.Length);
int line_count = script.TextLines.Count;
int text_index_size = line_count * 4;
file.Write (text_index_size);
long text_size_pos = file.BaseStream.Position;
file.Write ((int)0);
if (0 < script.Header.Length)
file.Write (script.Header);
if (0 < script.Code.Length)
file.Write (script.Code);
long text_index_pos = file.BaseStream.Position;
var index = new uint[line_count];
file.BaseStream.Seek (text_index_size, SeekOrigin.Current);
int i = 0;
long text_pos = file.BaseStream.Position;
uint current_pos = 0;
foreach (var line in script.TextLines)
{
index[i] = current_pos;
var text = Encodings.cp932.GetBytes (line.Text);
file.Write (text);
file.Write ((byte)0);
++i;
current_pos += (uint)text.Length + 1;
}
uint text_size = (uint)(file.BaseStream.Position - text_pos);
if (0 < script.Footer.Length)
file.Write (script.Footer);
uint file_size = (uint)(file.BaseStream.Position - file_size_pos);
file.BaseStream.Position = file_size_pos;
file.Write (file_size);
file.BaseStream.Position = text_size_pos;
file.Write (text_size);
file.BaseStream.Position = text_index_pos;
foreach (var offset in index)
file.Write (offset);
file.BaseStream.Position = file_size_pos + file_size;
}
}
}
}

626
ArcFormats/ArcXP3.cs Normal file
View File

@ -0,0 +1,626 @@
//! \file ArcXP3.cs
//! \date Wed Jul 16 13:58:17 2014
//! \brief KiriKiri engine archive implementation.
//
using System;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Text;
using System.Linq;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Diagnostics;
using GameRes.Utility;
using ZLibNet;
using GameRes.Formats.Strings;
using GameRes.Formats.Properties;
namespace GameRes.Formats.KiriKiri
{
public struct Xp3Segment
{
public bool IsCompressed;
public long Offset;
public uint Size;
public uint PackedSize;
}
public class Xp3Entry : PackedEntry
{
List<Xp3Segment> m_segments = new List<Xp3Segment>();
public bool IsEncrypted { get; set; }
public ICrypt Cipher { get; set; }
public ICollection<Xp3Segment> Segments { get { return m_segments; } }
public uint Hash { get; set; }
}
// Archive version 1: encrypt file first, then calculate checksum
// version 2: calculate checksum, then encrypt
[Export(typeof(ArchiveFormat))]
public class Xp3Opener : ArchiveFormat
{
public override string Tag { get { return "XP3"; } }
public override string Description { get { return "KiriKiri game engine resource archive"; } }
public override uint Signature { get { return 0x0d335058; } }
private static readonly ICrypt NoCryptAlgorithm = new NoCrypt();
public static readonly Dictionary<string, ICrypt> KnownSchemes = new Dictionary<string, ICrypt> {
{ arcStrings.ArcNoEncryption, NoCryptAlgorithm },
{ "Fate/Stay Night", new FateCrypt() },
{ "Swan Song", new SwanSongCrypt() },
{ "Cafe Sourire", new XorCrypt (0xcd) },
{ "Seirei Tenshou", new SeitenCrypt() },
{ "Okiba ga Nai!", new OkibaCrypt() },
};
public override ArcFile TryOpen (ArcView file)
{
if (!file.View.AsciiEqual (0, "XP3\x0d\x0a\x20\x0a\x1a\x8b\x67\x01"))
return null;
long dir_offset = file.View.ReadInt64 (0x0b);
if (0x17 == dir_offset)
{
if (1 != file.View.ReadUInt32 (0x13))
return null;
if (0x80 != file.View.ReadUInt32 (0x17))
return null;
dir_offset = file.View.ReadInt64 (0x20);
}
int header_type = file.View.ReadByte (dir_offset);
if (0 != header_type && 1 != header_type)
return null;
Stream header_stream;
if (0 == header_type) // read unpacked header
{
long header_size = file.View.ReadInt64 (dir_offset+1);
if (header_size > uint.MaxValue)
return null;
header_stream = file.CreateStream (dir_offset+9, (uint)header_size);
}
else // read packed header
{
long packed_size = file.View.ReadInt64 (dir_offset+1);
if (packed_size > uint.MaxValue)
return null;
long header_size = file.View.ReadInt64 (dir_offset+9);
using (var input = file.CreateStream (dir_offset+17, (uint)packed_size))
header_stream = ZLibCompressor.DeCompress (input);
}
var crypt_algorithm = new Lazy<ICrypt> (QueryCryptAlgorithm);
var dir = new List<Entry>();
dir_offset = 0;
using (var header = new BinaryReader (header_stream, Encoding.Unicode))
{
while (-1 != header.PeekChar())
{
uint entry_signature = header.ReadUInt32();
if (0x656c6946 != entry_signature) // "File"
{
break;
}
long entry_size = header.ReadInt64();
dir_offset += 12 + entry_size;
var entry = new Xp3Entry();
while (entry_size > 0)
{
uint section = header.ReadUInt32();
long section_size = header.ReadInt64();
entry_size -= 12;
if (section_size > entry_size)
break;
entry_size -= section_size;
long next_section_pos = header.BaseStream.Position + section_size;
switch (section)
{
case 0x6f666e69: // "info"
{
if (entry.Size != 0 || !string.IsNullOrEmpty (entry.Name))
{
goto NextEntry; // ambiguous entry, ignore
}
entry.IsEncrypted = 0 != header.ReadUInt32();
long file_size = header.ReadInt64();
long packed_size = header.ReadInt64();
if (file_size > uint.MaxValue || packed_size > uint.MaxValue)
{
goto NextEntry;
}
entry.IsPacked = file_size != packed_size;
entry.Size = (uint)packed_size;
entry.UnpackedSize = (uint)file_size;
int name_size = header.ReadInt16();
if (name_size > 0x100 || name_size <= 0)
{
goto NextEntry;
}
if (entry.IsEncrypted)
entry.Cipher = crypt_algorithm.Value;
else
entry.Cipher = NoCryptAlgorithm;
char[] name = header.ReadChars (name_size);
entry.Name = new string (name);
entry.Type = FormatCatalog.Instance.GetTypeFromName (entry.Name);
break;
}
case 0x6d676573: // "segm"
{
int segment_count = (int)(section_size / 0x1c);
if (segment_count > 0)
{
for (int i = 0; i < segment_count; ++i)
{
bool compressed = 0 != header.ReadInt32();
long segment_offset = header.ReadInt64();
long segment_size = header.ReadInt64();
long segment_packed_size = header.ReadInt64();
if (segment_offset > file.MaxOffset || segment_size > file.MaxOffset
|| segment_packed_size > file.MaxOffset)
{
goto NextEntry;
}
var segment = new Xp3Segment {
IsCompressed = compressed,
Offset = segment_offset,
Size = (uint)segment_size,
PackedSize = (uint)segment_packed_size
};
entry.Segments.Add (segment);
}
entry.Offset = entry.Segments.First().Offset;
}
break;
}
case 0x726c6461: // "adlr"
if (4 == section_size)
entry.Hash = header.ReadUInt32();
break;
default: // unknown section
break;
}
header.BaseStream.Position = next_section_pos;
}
if (!string.IsNullOrEmpty (entry.Name) && entry.Segments.Any())
dir.Add (entry);
NextEntry:
header.BaseStream.Position = dir_offset;
}
}
return new ArcFile (file, this, dir);
}
public override Stream OpenEntry (ArcFile arc, Entry entry)
{
var xp3_entry = entry as Xp3Entry;
if (null == xp3_entry || !xp3_entry.Segments.Any())
return arc.File.CreateStream (entry.Offset, entry.Size);
if (1 == xp3_entry.Segments.Count && !xp3_entry.IsEncrypted)
{
var segment = xp3_entry.Segments.First();
if (segment.IsCompressed)
return new ZLibStream (arc.File.CreateStream (segment.Offset, segment.PackedSize),
CompressionMode.Decompress);
else
return arc.File.CreateStream (segment.Offset, segment.Size);
}
return new Xp3Stream (arc.File, xp3_entry);
}
string m_scheme = GetDefaultScheme();
ICrypt QueryCryptAlgorithm ()
{
var widget = new GUI.WidgetXP3 (m_scheme);
var args = new ParametersRequestEventArgs
{
Notice = arcStrings.ArcEncryptedNotice,
InputWidget = widget,
};
FormatCatalog.Instance.InvokeParametersRequest (this, args);
if (!args.InputResult)
throw new OperationCanceledException();
m_scheme = widget.GetScheme();
if (null != m_scheme)
{
ICrypt algorithm;
if (KnownSchemes.TryGetValue (m_scheme, out algorithm))
{
Settings.Default.XP3Scheme = m_scheme;
return algorithm;
}
}
return NoCryptAlgorithm;
}
public static string GetDefaultScheme ()
{
string scheme = Settings.Default.XP3Scheme;
if (!string.IsNullOrEmpty (scheme) && KnownSchemes.ContainsKey (scheme))
return scheme;
else
return arcStrings.ArcNoEncryption;
}
static uint GetFileCheckSum (Stream src)
{
// compute file checksum via adler32.
// src's file pointer should be reset to zero.
var sum = new Adler32();
byte[] buf = new byte[64*1024];
for (;;)
{
int read = src.Read (buf, 0, buf.Length);
if (0 == read) break;
sum.Update (buf, 0, read);
}
return sum.Value;
}
}
public class Xp3Stream : Stream
{
ArcView m_file;
Xp3Entry m_entry;
IEnumerator<Xp3Segment> m_segment;
Stream m_stream;
long m_offset = 0;
bool m_eof = false;
public override bool CanRead { get { return true; } }
public override bool CanSeek { get { return false; } }
public override bool CanWrite { get { return false; } }
public override long Length { get { return m_entry.UnpackedSize; } }
public override long Position
{
get { return m_offset; }
set { throw new NotSupportedException ("Xp3Stream.Position not supported."); }
}
public Xp3Stream (ArcView file, Xp3Entry entry)
{
m_file = file;
m_entry = entry;
m_segment = entry.Segments.GetEnumerator();
NextSegment();
}
private void NextSegment ()
{
if (!m_segment.MoveNext())
{
m_eof = true;
return;
}
if (null != m_stream)
m_stream.Dispose();
var segment = m_segment.Current;
if (segment.IsCompressed)
m_stream = new ZLibStream (m_file.CreateStream (segment.Offset, segment.PackedSize),
CompressionMode.Decompress);
else
m_stream = m_file.CreateStream (segment.Offset, segment.Size);
}
public override int Read (byte[] buffer, int offset, int count)
{
int total = 0;
while (!m_eof && count > 0)
{
int read = m_stream.Read (buffer, offset, count);
m_entry.Cipher.Decrypt (m_entry, m_offset, buffer, offset, read);
m_offset += read;
total += read;
offset += read;
count -= read;
if (0 != count)
NextSegment();
}
return total;
}
public override int ReadByte ()
{
int b = -1;
while (!m_eof)
{
b = m_stream.ReadByte();
if (-1 != b)
{
b = m_entry.Cipher.Decrypt (m_entry, m_offset++, (byte)b);
break;
}
NextSegment();
}
return b;
}
public override void Flush ()
{
}
public override long Seek (long offset, SeekOrigin origin)
{
throw new NotSupportedException ("Xp3Stream.Seek method is not supported");
}
public override void SetLength (long length)
{
throw new NotSupportedException ("Xp3Stream.SetLength method is not supported");
}
public override void Write (byte[] buffer, int offset, int count)
{
throw new NotSupportedException ("Xp3Stream.Write method is not supported");
}
public override void WriteByte (byte value)
{
throw new NotSupportedException("Xp3Stream.WriteByte method is not supported");
}
#region IDisposable Members
bool disposed = false;
protected override void Dispose (bool disposing)
{
if (!disposed)
{
m_file = null;
if (null != m_stream)
{
m_stream.Dispose();
m_stream = null;
}
disposed = true;
base.Dispose (disposing);
}
}
#endregion
}
public abstract class ICrypt
{
public abstract byte Decrypt (Xp3Entry entry, long offset, byte value);
public virtual void Decrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count)
{
for (int i = 0; i < count; ++i)
values[pos+i] = this.Decrypt (entry, offset+i, values[pos+i]);
}
public virtual void Encrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count)
{
throw new NotImplementedException ("Encryption method not implemented");
}
}
public class NoCrypt : ICrypt
{
public override byte Decrypt (Xp3Entry entry, long offset, byte value)
{
return value;
}
public override void Decrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count)
{
return;
}
public override void Encrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count)
{
return;
}
}
internal class FateCrypt : ICrypt
{
public override byte Decrypt (Xp3Entry entry, long offset, byte value)
{
byte result = (byte)(value ^ 0x36);
if (0x13 == offset)
result ^= 1;
else if (0x2ea29 == offset)
result ^= 3;
return result;
}
public override void Decrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count)
{
for (int i = 0; i < count; ++i)
{
values[pos+i] ^= 0x36;
}
if (offset > 0x2ea29)
return;
if (offset + count > 0x2ea29)
values[pos+0x2ea29-offset] ^= 3;
if (offset > 0x13)
return;
if (offset + count > 0x13)
values[pos+0x13-offset] ^= 1;
}
public override void Encrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count)
{
Decrypt (entry, offset, values, pos, count);
}
}
internal class XorCrypt : ICrypt
{
private byte m_key;
public byte Key
{
get { return m_key; }
set { m_key = value; }
}
public XorCrypt (uint key)
{
m_key = (byte)key;
}
public override byte Decrypt (Xp3Entry entry, long offset, byte value)
{
return (byte)(value ^ m_key);
}
public override void Decrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count)
{
for (int i = 0; i < count; ++i)
{
values[pos+i] ^= m_key;
}
}
public override void Encrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count)
{
Decrypt (entry, offset, values, pos, count);
}
}
internal class SwanSongCrypt : ICrypt
{
static private byte Adjust (uint hash, out int shift)
{
int cl = (int)(hash & 0xff);
if (0 == cl) cl = 0x0f;
shift = cl & 7;
int ch = (int)((hash >> 8) & 0xff);
if (0 == ch) ch = 0xf0;
return (byte)ch;
}
public override byte Decrypt (Xp3Entry entry, long offset, byte value)
{
int shift;
byte xor = Adjust (entry.Hash, out shift);
uint data = (uint)(value ^ xor);
return (byte)((data >> shift) | (data << (8 - shift)));
}
public override void Decrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count)
{
int shift;
byte xor = Adjust (entry.Hash, out shift);
for (int i = 0; i < count; ++i)
{
uint data = (uint)(values[pos+i] ^ xor);
values[pos+i] = (byte)((data >> shift) | (data << (8 - shift)));
}
}
public override void Encrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count)
{
int shift;
byte xor = Adjust (entry.Hash, out shift);
for (int i = 0; i < count; ++i)
{
uint data = values[pos+i];
data = (byte)((data << shift) | (data >> (8 - shift)));
values[pos+i] = (byte)(data ^ xor);
}
}
}
internal class SeitenCrypt : ICrypt
{
public override byte Decrypt (Xp3Entry entry, long offset, byte value)
{
uint key = entry.Hash ^ (uint)offset;
if (0 != (key & 2))
{
int ecx = (int)key & 0x18;
value ^= (byte)((key >> ecx) | (key >> (ecx & 8)));
}
if (0 != (key & 4))
{
value += (byte)key;
}
if (0 != (key & 8))
{
value -= (byte)(key >> (int)(key & 0x10));
}
return value;
}
public override void Encrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count)
{
for (int i = 0; i < count; ++i)
{
uint key = entry.Hash ^ (uint)offset;
if (0 != (key & 8))
{
values[pos+i] += (byte)(key >> (int)(key & 0x10));
}
if (0 != (key & 4))
{
values[pos+i] -= (byte)key;
}
if (0 != (key & 2))
{
int ecx = (int)key & 0x18;
values[pos+i] ^= (byte)((key >> ecx) | (key >> (ecx & 8)));
}
}
}
}
internal class OkibaCrypt : ICrypt
{
public override byte Decrypt (Xp3Entry entry, long offset, byte value)
{
if (offset < 0x65)
return (byte)(value ^ (byte)(entry.Hash >> 4));
uint key = entry.Hash;
// 0,1,2,3 -> 1,0,3,2
key = ((key & 0xff0000) << 8) | ((key & 0xff000000) >> 8)
| ((key & 0xff00) >> 8) | ((key & 0xff) << 8);
key >>= 8 * ((int)(offset - 0x65) & 3);
return (byte)(value ^ (byte)key);
}
public override void Decrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count)
{
int i = 0;
if (offset < 0x65)
{
uint key = entry.Hash >> 4;
int limit = Math.Min (count, (int)(0x65 - offset));
for (; i < limit; ++i)
{
values[pos+i] ^= (byte)key;
++offset;
}
}
if (i < count)
{
offset -= 0x65;
uint key = entry.Hash;
key = ((key & 0xff0000) << 8) | ((key & 0xff000000) >> 8)
| ((key & 0xff00) >> 8) | ((key & 0xff) << 8);
do
{
values[pos+i] ^= (byte)(key >> (8 * ((int)offset & 3)));
++offset;
}
while (++i < count);
}
}
public override void Encrypt (Xp3Entry entry, long offset, byte[] values, int pos, int count)
{
Decrypt (entry, offset, values, pos, count);
}
}
}

193
ArcFormats/ArcYPF.cs Normal file
View File

@ -0,0 +1,193 @@
//! \file ArcYPF.cs
//! \date Mon Jul 14 14:40:06 2014
//! \brief YPF resource format implementation.
//
using System;
using System.IO;
using System.Text;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using ZLibNet;
using GameRes.Formats.Strings;
using GameRes.Formats.Properties;
namespace GameRes.Formats
{
[Export(typeof(ArchiveFormat))]
public class YpfOpener : ArchiveFormat
{
public override string Tag { get { return "YPF"; } }
public override string Description { get { return "Yu-Ris game engine resource archive"; } }
public override uint Signature { get { return 0x00465059; } }
private const uint DefaultKey = 0xffffffff;
public override ArcFile TryOpen (ArcView file)
{
uint count = file.View.ReadUInt32 (8);
uint dir_size = file.View.ReadUInt32 (12);
if (dir_size < count * 0x17)
return null;
if (0 != ((count - 1) >> 20))
return null;
// Reserve (0x20, dir_size)
var parser = new Parser (file, count, dir_size);
uint key = QueryEncryptionKey();
var dir = parser.ScanDir (key);
if (0 == dir.Count)
return null;
return new ArcFile (file, this, dir);
}
public override Stream OpenEntry (ArcFile arc, Entry entry)
{
var input = arc.File.CreateStream (entry.Offset, entry.Size);
var packed_entry = entry as PackedEntry;
if (null == packed_entry || !packed_entry.IsPacked)
return input;
else
return new ZLibStream (input, CompressionMode.Decompress);
}
uint m_last_key = Settings.Default.YPFKey;
uint QueryEncryptionKey ()
{
uint? key = m_last_key;
if (m_last_key > 0xff)
key = null;
var widget = new GUI.WidgetYPF (key);
var args = new ParametersRequestEventArgs
{
Notice = arcStrings.YPFNotice,
InputWidget = widget,
};
FormatCatalog.Instance.InvokeParametersRequest (this, args);
if (!args.InputResult)
throw new OperationCanceledException();
key = widget.GetKey();
m_last_key = null != key && key.Value < 0x100 ? key.Value : DefaultKey;
Settings.Default.YPFKey = m_last_key;
return m_last_key;
}
private class Parser
{
ArcView m_file;
uint m_version;
uint m_count;
uint m_dir_size;
public Parser (ArcView file, uint count, uint dir_size)
{
m_file = file;
m_count = count;
m_dir_size = dir_size;
m_version = file.View.ReadUInt32 (4);
}
// 4-name_checksum, 1-name_count, *-name, 1-file_type
// 1-pack_flag, 4-size, 4-packed_size, 4-offset, 4-packed_adler32
public List<Entry> ScanDir (uint key)
{
uint dir_offset = 0x20;
uint dir_remaining = m_dir_size;
uint num;
var dir = new List<Entry> ((int)m_count);
for (num = 0; num < m_count; ++num)
{
if (dir_remaining < 0x17)
break;
dir_remaining -= 0x17;
uint name_size = Decrypt ((byte)(m_file.View.ReadByte (dir_offset+4) ^ 0xff));
if (name_size > dir_remaining)
break;
dir_remaining -= name_size;
dir_offset += 5;
if (0 == name_size)
break;
if (0xffffffff == key)
{
if (name_size < 4)
break;
// assume filename contains '.' and 3-characters extension.
key = (uint)(m_file.View.ReadByte (dir_offset+name_size-4) ^ 0x2e);
}
byte[] raw_name = new byte[name_size];
for (int i = 0; i < name_size; ++i)
{
raw_name[i] = (byte)(m_file.View.ReadByte (dir_offset) ^ key);
++dir_offset;
}
string name = Encodings.cp932.GetString (raw_name);
// 0x0F7: 0-ybn, 1-bmp, 2-png, 3-jpg, 4-gif, 5-avi, 6-wav, 7-ogg, 8-psd
// 0x122, 0x12C, 0x196: 0-ybn, 1-bmp, 2-png, 3-jpg, 4-gif, 5-wav, 6-ogg, 7-psd
int type_id = m_file.View.ReadByte (dir_offset);
string type = "";
switch (type_id)
{
case 0:
type = "script";
break;
case 1: case 2: case 3: case 4:
type = "image";
break;
case 5:
type = 0xf7 == m_version ? "video" : "audio";
break;
case 6:
case 7:
type = "audio";
break;
}
var entry = new PackedEntry { Name = name, Type = type };
entry.IsPacked = 1 == m_file.View.ReadByte (dir_offset+1);
entry.UnpackedSize = m_file.View.ReadUInt32 (dir_offset+2);
entry.Size = m_file.View.ReadUInt32 (dir_offset+6);
entry.Offset = m_file.View.ReadUInt32 (dir_offset+10);
if (entry.CheckPlacement (m_file.MaxOffset))
dir.Add (entry);
dir_offset += 0x12;
}
return dir;
}
static readonly byte[] s_crypt_table = {
0x03,0x48,0x06,0x35, // 0x122, 0x196
0x0C,0x10,0x11,0x19,0x1C,0x1E, // 0x0F7
0x09,0x0B,0x0D,0x13,0x15,0x1B, // 0x12C
0x20,0x23,0x26,0x29,
0x2C,0x2F,0x2E,0x32,
};
// 0xFF 0x0F7 "Four-Leaf" adler32
// 0x34 0x122 "Neko Koi!" crc32
// 0x28 0x12C "Suzukaze no Melt" (no recovery - 00 00 00 00)
// 0xFF 0x196 "Mamono Musume-tachi to no Rakuen ~Slime & Scylla~"
public uint Decrypt (byte value)
{
int pos = s_crypt_table.Length - 0x14;
if (m_version >= 0x100)
{
pos -= 4;
if (m_version >= 0x12c && m_version < 0x196)
pos += 10;
}
pos = Array.FindIndex (s_crypt_table, pos, x => x == value);
if (-1 == pos)
return value;
if (0 != (pos & 1))
return s_crypt_table[pos-1];
else
return s_crypt_table[pos+1];
}
}
}
}

677
ArcFormats/Blowfish.cs Normal file
View File

@ -0,0 +1,677 @@
/****************************************************************************
|
| Copyright (c) 2007 Novell, Inc.
| All Rights Reserved.
|
| This program is free software; you can redistribute it and/or
| modify it under the terms of version 2 of the GNU General Public License as
| published by the Free Software Foundation.
|
| This program is distributed in the hope that it will be useful,
| but WITHOUT ANY WARRANTY; without even the implied warranty of
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
| GNU General Public License for more details.
|
| You should have received a copy of the GNU General Public License
| along with this program; if not, contact Novell, Inc.
|
| To contact Novell about this file by physical or electronic mail,
| you may find current contact information at www.novell.com
|
| Author: Russ Young
| Thanks to: Bruce Schneier / Counterpane Labs
| for the Blowfish encryption algorithm and
| reference implementation. http://www.schneier.com/blowfish.html
|***************************************************************************/
using System;
using System.Text;
using System.IO;
namespace Simias.Encryption
{
/// <summary>
/// Class that provides blowfish encryption.
/// </summary>
public class Blowfish
{
const int N = 16;
const int KEYBYTES = 8;
static uint[] _P =
{
0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0,
0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b
};
static uint[,] _S =
{
{
0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96,
0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 0x0d95748f, 0x728eb658,
0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e,
0x6c9e0e8b, 0xb01e8a3e, 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 0x55ca396a, 0x2aab10b6,
0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c,
0x7a325381, 0x28958677, 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 0xef845d5d, 0xe98575b1,
0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a,
0x670c9c61, 0xabd388f0, 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 0xa1f1651d, 0x39af0176,
0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706,
0x1bfedf72, 0x429b023d, 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 0xe3fe501a, 0xb6794c3b,
0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c,
0xcc814544, 0xaf5ebd09, 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 0x5579c0bd, 0x1a60320a,
0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760,
0x53317b48, 0x3e00df82, 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 0x695b27b0, 0xbbca58c8,
0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33,
0x62fb1341, 0xcee4c6e8, 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 0xd08ed1d0, 0xafc725e0,
0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777,
0xea752dfe, 0x8b021fa1, 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 0x165fa266, 0x80957705,
0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e,
0x226800bb, 0x57b8e0af, 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, 0x83260376, 0x6295cfa9,
0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f,
0xf296ec6b, 0x2a0dd915, 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a
},
{
0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d,
0x9cee60b8, 0x8fedb266, 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, 0x3f54989a, 0x5b429d65,
0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9,
0x3c971814, 0x6b6a70a1, 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, 0xb03ada37, 0xf0500c0d,
0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc,
0xc8b57634, 0x9af3dda7, 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 0x4e548b38, 0x4f6db908,
0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124,
0x501adde6, 0x9f84cd87, 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 0xef1c1847, 0x3215d908,
0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b,
0x3c11183b, 0x5924a509, 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa,
0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d,
0x1939260f, 0x19c27960, 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, 0xc332ddef, 0xbe6c5aa5,
0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96,
0x0334fe1e, 0xaa0363cf, 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca,
0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77,
0x11ed935f, 0x16681281, 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, 0xcdb30aeb, 0x532e3054,
0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea,
0xdb6c4f15, 0xfacb4fd0, 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, 0xcf62a1f2, 0x5b8d2646,
0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea,
0x1dadf43e, 0x233f7061, 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, 0xa6078084, 0x19f8509e,
0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd,
0x675fda79, 0xe3674340, 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7
},
{
0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7,
0xbcf46b2e, 0xd4a20068, 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, 0x4d95fc1d, 0x96b591af,
0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4,
0x0a2c86da, 0xe9b66dfb, 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, 0xaace1e7c, 0xd3375fec,
0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332,
0x6841e7f7, 0xca7820fb, 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, 0x55a867bc, 0xa1159a58,
0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22,
0x48c1133f, 0xc70f86dc, 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, 0x257b7834, 0x602a9c60,
0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99,
0xde720c8c, 0x2da2f728, 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, 0x0a476341, 0x992eff74,
0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3,
0xb5390f92, 0x690fed0b, 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, 0x37392eb3, 0xcc115979,
0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa,
0x3d25bdd8, 0xe2e1c3c9, 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, 0x9dbc8057, 0xf0f7c086,
0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24,
0x55464299, 0xbf582e61, 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, 0x7aeb2661, 0x8b1ddf84,
0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09,
0x662d09a1, 0xc4324633, 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, 0xdcb7da83, 0x573906fe,
0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0,
0x006058aa, 0x30dc7d62, 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, 0x6f05e409, 0x4b7c0188,
0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8,
0xa28514d9, 0x6c51133c, 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0
},
{
0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742,
0xd3822740, 0x99bc9bbe, 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 0x5748ab2f, 0xbc946e79,
0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a,
0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 0x2826a2f9, 0xa73a3ae1,
0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797,
0x2cf0b7d9, 0x022b8b51, 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 0xe029ac71, 0xe019a5e6,
0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba,
0x03a16125, 0x0564f0bd, 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 0x7533d928, 0xb155fdf5,
0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce,
0x5121ce64, 0x774fbe32, 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 0xb39a460a, 0x6445c0dd,
0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb,
0x8d6612ae, 0xbf3c6f47, 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 0x4040cb08, 0x4eb4e2cc,
0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc,
0xbb3a792b, 0x344525bd, 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 0x1a908749, 0xd44fbd9a,
0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a,
0x0f91fc71, 0x9b941525, 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 0xe0ec6e0e, 0x1698db3b,
0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e,
0xe60b6f47, 0x0fe3f11d, 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 0xf523f357, 0xa6327623,
0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a,
0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 0x53113ec0, 0x1640e3d3,
0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c,
0x01c36ae4, 0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6
}
};
uint[] P;
uint[,] S;
/// <summary>
/// Constructs and initializes a blowfish instance with the supplied key.
/// </summary>
/// <param name="key">The key to cipher with.</param>
public Blowfish(byte[] key)
{
short i;
short j;
short k;
uint data;
uint datal;
uint datar;
P = _P.Clone() as uint[];
S = _S.Clone() as uint[,];
j = 0;
for (i = 0; i < N + 2; ++i)
{
data = 0x00000000;
for (k = 0; k < 4; ++k)
{
data = (data << 8) | key[j];
j++;
if (j >= key.Length)
{
j = 0;
}
}
P[i] = P[i] ^ data;
}
datal = 0x00000000;
datar = 0x00000000;
for (i = 0; i < N + 2; i += 2)
{
Encipher(ref datal, ref datar);
P[i] = datal;
P[i + 1] = datar;
}
for (i = 0; i < 4; ++i)
{
for (j = 0; j < 256; j += 2)
{
Encipher(ref datal, ref datar);
S[i,j] = datal;
S[i,j + 1] = datar;
}
}
}
/// <summary>
///
/// </summary>
/// <param name="x"></param>
/// <returns></returns>
private uint F(uint x)
{
ushort a;
ushort b;
ushort c;
ushort d;
uint y;
d = (ushort)(x & 0x00FF);
x >>= 8;
c = (ushort)(x & 0x00FF);
x >>= 8;
b = (ushort)(x & 0x00FF);
x >>= 8;
a = (ushort)(x & 0x00FF);
//y = ((S[0][a] + S[1][b]) ^ S[2][c]) + S[3][d];
y = S[0,a] + S[1,b];
y = y ^ S[2,c];
y = y + S[3,d];
return y;
}
/// <summary>
/// Encrypts a byte array in place.
/// </summary>
/// <param name="data">The array to encrypt.</param>
/// <param name="length">The amount to encrypt.</param>
public void Encipher(byte[] data, int length)
{
uint xl, xr;
if ((length % 8) != 0)
throw new Exception("Invalid Length");
for (int i = 0; i < length; i+=8)
{
// Encode the data in 8 byte blocks.
xl = (uint)((data[i] << 24) | (data[i+1] << 16) | (data[i+2] << 8) | data[i+3]);
xr = (uint)((data[i+4] << 24) | (data[i+5] << 16) | (data[i+6] << 8) | data[i+7]);
Encipher(ref xl, ref xr);
// Now Replace the data.
data[i] = (byte)(xl >> 24);
data[i+1] = (byte)(xl >> 16);
data[i+2] = (byte)(xl >> 8);
data[i+3] = (byte)(xl);
data[i+4] = (byte)(xr >> 24);
data[i+5] = (byte)(xr >> 16);
data[i+6] = (byte)(xr >> 8);
data[i+7] = (byte)(xr);}
}
/// <summary>
/// Encrypts 8 bytes of data (1 block)
/// </summary>
/// <param name="xl">The left part of the 8 bytes.</param>
/// <param name="xr">The right part of the 8 bytes.</param>
private void Encipher(ref uint xl, ref uint xr)
{
uint Xl;
uint Xr;
uint temp;
short i;
Xl = xl;
Xr = xr;
for (i = 0; i < N; ++i)
{
Xl = Xl ^ P[i];
Xr = F(Xl) ^ Xr;
temp = Xl;
Xl = Xr;
Xr = temp;
}
temp = Xl;
Xl = Xr;
Xr = temp;
Xr = Xr ^ P[N];
Xl = Xl ^ P[N + 1];
xl = Xl;
xr = Xr;
}
/// <summary>
/// Decrypts a byte array in place.
/// </summary>
/// <param name="data">The array to decrypt.</param>
/// <param name="length">The amount to decrypt.</param>
public void Decipher(byte[] data, int length)
{
uint xl, xr;
if ((length % 8) != 0)
throw new Exception("Invalid Length");
for (int i = 0; i < length; i += 8)
{
// Encode the data in 8 byte blocks.
xl = (uint)(data[i] | (data[i+1] << 8) | (data[i+2] << 16) | (data[i+3] << 24));
xr = (uint)(data[i+4] | (data[i+5] << 8) | (data[i+6] << 16) | (data[i+7] << 24));
Decipher(ref xl, ref xr);
// Now Replace the data.
data[i] = (byte)(xl);
data[i+1] = (byte)(xl >> 8);
data[i+2] = (byte)(xl >> 16);
data[i+3] = (byte)(xl >> 24);
data[i+4] = (byte)(xr);
data[i+5] = (byte)(xr >> 8);
data[i+6] = (byte)(xr >> 16);
data[i+7] = (byte)(xr >> 24);
}
}
/// <summary>
/// Decrypts 8 bytes of data (1 block)
/// </summary>
/// <param name="xl">The left part of the 8 bytes.</param>
/// <param name="xr">The right part of the 8 bytes.</param>
public void Decipher(ref uint xl, ref uint xr)
{
uint Xl;
uint Xr;
uint temp;
short i;
Xl = xl;
Xr = xr;
for (i = N + 1; i > 1; --i)
{
Xl = Xl ^ P[i];
Xr = F(Xl) ^ Xr;
/* Exchange Xl and Xr */
temp = Xl;
Xl = Xr;
Xr = temp;
}
/* Exchange Xl and Xr */
temp = Xl;
Xl = Xr;
Xr = temp;
Xr = Xr ^ P[1];
Xl = Xl ^ P[0];
xl = Xl;
xr = Xr;
}
}
public class BlowfishStream : Stream
{
class CBState : IAsyncResult
{
internal AsyncCallback callback;
internal object state;
internal byte[] buffer;
internal IAsyncResult result;
internal CBState(AsyncCallback callback, object state, byte[] buffer)
{
this.callback = callback;
this.state = state;
this.buffer = buffer;
}
#region IAsyncResult Members
public object AsyncState
{
get
{
return state;
}
}
public bool CompletedSynchronously
{
get
{
return result.CompletedSynchronously;
}
}
public System.Threading.WaitHandle AsyncWaitHandle
{
get
{
return result.AsyncWaitHandle;
}
}
public bool IsCompleted
{
get
{
return result.IsCompleted;
}
}
#endregion
}
public enum Target
{
Encrypted,
Normal
};
Stream stream;
Blowfish bf;
Target target;
BlowfishStream(Stream stream, Blowfish bf, Target target)
{
this.stream = stream;
this.bf = bf;
this.target = target;
}
/// <summary>
/// Returns true if the stream support reads.
/// </summary>
public override bool CanRead
{
get {return stream.CanRead;}
}
/// <summary>
/// Returns true is the stream supports seeks.
/// </summary>
public override bool CanSeek
{
get {return stream.CanSeek;}
}
/// <summary>
/// Returns true if the stream supports writes.
/// </summary>
public override bool CanWrite
{
get {return stream.CanWrite;}
}
/// <summary>
/// Returns the length of the stream.
/// </summary>
public override long Length
{
get {return stream.Length;}
}
/// <summary>
/// Gets or Sets the posistion of the stream.
/// </summary>
public override long Position
{
get {return stream.Position;}
set {stream.Position = value;}
}
/// <summary>
/// Flushes the stream.
/// </summary>
public override void Flush()
{
stream.Flush();
}
/// <summary>
/// Read data from the stream and encrypt it.
/// </summary>
/// <param name="buffer">The buffer to read into.</param>
/// <param name="offset">The offset in the buffer to begin storing data.</param>
/// <param name="count">The number of bytes to read.</param>
/// <returns></returns>
public override int Read(byte[] buffer, int offset, int count)
{
int bytesRead = stream.Read(buffer, offset, count);
if (target == Target.Normal)
bf.Encipher(buffer, bytesRead);
else
bf.Decipher(buffer, bytesRead);
return bytesRead;
}
/// <summary>
/// Write data to the stream after decrypting it.
/// </summary>
/// <param name="buffer">The buffer containing the data to write.</param>
/// <param name="offset">The offset in the buffer where the data begins.</param>
/// <param name="count">The number of bytes to write.</param>
public override void Write(byte[] buffer, int offset, int count)
{
if (target == Target.Normal)
bf.Decipher(buffer, count);
else
bf.Encipher(buffer, count);
stream.Write(buffer, offset, count);
}
/// <summary>
///
/// </summary>
/// <param name="buffer"></param>
/// <param name="offset"></param>
/// <param name="count"></param>
/// <param name="callback"></param>
/// <param name="state"></param>
/// <returns></returns>
public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
{
CBState cbs = new CBState(callback, state, buffer);
cbs.result = base.BeginRead (buffer, offset, count, new AsyncCallback(ReadComplete), cbs);
return cbs;
}
/// <summary>
///
/// </summary>
/// <param name="asyncResult"></param>
/// <returns></returns>
public override int EndRead(IAsyncResult asyncResult)
{
CBState cbs = (CBState)asyncResult.AsyncState;
int bytesRead = base.EndRead (cbs.result);
if (target == Target.Normal)
bf.Encipher(cbs.buffer, bytesRead);
else
bf.Decipher(cbs.buffer, bytesRead);
return bytesRead;
}
/// <summary>
/// The Read has completed.
/// </summary>
/// <param name="result">The result of the async write.</param>
private void ReadComplete(IAsyncResult result)
{
CBState cbs = (CBState)result.AsyncState;
cbs.callback(cbs);
}
/// <summary>
///
/// </summary>
/// <param name="buffer"></param>
/// <param name="offset"></param>
/// <param name="count"></param>
/// <param name="callback"></param>
/// <param name="state"></param>
/// <returns></returns>
public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
{
if (target == Target.Normal)
bf.Decipher(buffer, count);
else
bf.Encipher(buffer, count);
return base.BeginWrite (buffer, offset, count, callback, state);
}
/// <summary>
/// Move the current stream posistion to the specified location.
/// </summary>
/// <param name="offset">The offset from the origin to seek.</param>
/// <param name="origin">The origin to seek from.</param>
/// <returns>The new position.</returns>
public override long Seek(long offset, SeekOrigin origin)
{
return stream.Seek(offset, origin);
}
/// <summary>
/// Set the stream length.
/// </summary>
/// <param name="value">The length to set.</param>
public override void SetLength(long value)
{
stream.SetLength(value);
}
}
}

342
ArcFormats/ImageHG3.cs Normal file
View File

@ -0,0 +1,342 @@
//! \file ImageHG3.cs
//! \date Sat Jul 19 17:31:09 2014
//! \brief Frontwing HG3 image format implementation.
//
using System;
using System.IO;
using System.ComponentModel.Composition;
using System.Windows.Media.Imaging;
using System.Windows.Media;
using ZLibNet;
using GameRes.Utility;
namespace GameRes.Formats
{
[Export(typeof(ImageFormat))]
public class Hg3Format : ImageFormat
{
public override string Tag { get { return "HG3"; } }
public override string Description { get { return "Frontwing proprietary image format"; } }
public override uint Signature { get { return 0x332d4748; } }
public override ImageMetaData ReadMetaData (Stream stream)
{
var header = new byte[0x4c];
if (0x4c != stream.Read (header, 0, header.Length))
return null;
if (LittleEndian.ToUInt32 (header, 0) != Signature)
return null;
if (LittleEndian.ToUInt32 (header, 4) != 0x0c)
return null;
if (!Binary.AsciiEqual (header, 0x14, "stdinfo\0"))
return null;
if (0x38 != LittleEndian.ToUInt32 (header, 0x1c))
return null;
if (0x20 != LittleEndian.ToUInt32 (header, 0x2c))
return null;
uint width = LittleEndian.ToUInt32 (header, 0x24); // @@L0
uint height = LittleEndian.ToUInt32 (header, 0x28);
int pos_x = LittleEndian.ToInt32 (header, 0x30);
int pos_y = LittleEndian.ToInt32 (header, 0x34);
pos_x -= LittleEndian.ToInt32 (header, 0x44);
pos_y -= LittleEndian.ToInt32 (header, 0x48);
return new ImageMetaData
{
Width = width,
Height = height,
OffsetX = pos_x,
OffsetY = pos_y,
BPP = 32,
};
}
public override ImageData Read (Stream stream, ImageMetaData info)
{
stream.Position = 0x40;
bool flipped = 0 == (stream.ReadByte() & 1) || info.OffsetY < 0;
stream.Position = 0x4c;
var header = new byte[0x28];
if (0x28 != stream.Read (header, 0, header.Length))
return null;
if (!Binary.AsciiEqual (header, "img0000\0"))
return null;
uint data_size = LittleEndian.ToUInt32 (header, 0x0c);
if (data_size < 0x18)
return null;
if (info.Height != LittleEndian.ToUInt32 (header, 0x14))
return null;
uint packed2_size = LittleEndian.ToUInt32 (header, 0x18);
uint unpacked2_size = LittleEndian.ToUInt32 (header, 0x1c);
uint packed1_size = LittleEndian.ToUInt32 (header, 0x20);
uint unpacked1_size = LittleEndian.ToUInt32 (header, 0x24);
if (packed2_size + packed1_size < packed2_size)
return null;
if (unpacked2_size + unpacked1_size < unpacked2_size)
return null;
long data_pos = stream.Position;
using (var unpacked2 = ZLibCompressor.DeCompress (stream))
{
stream.Position = data_pos + packed2_size;
using (var unpacked1 = ZLibCompressor.DeCompress (stream))
{
var decoder = new Decoder (unpacked1.GetBuffer(), unpacked1_size,
unpacked2.GetBuffer(), unpacked2_size,
info.Width, info.Height);
decoder.Unpack();
var pixels = decoder.Data;
int stride = (int)info.Width * 4;
var bitmap = BitmapSource.Create ((int)info.Width, (int)info.Height, 96, 96,
PixelFormats.Bgra32, null, pixels, stride);
if (flipped)
{
var flipped_bitmap = new TransformedBitmap();
flipped_bitmap.BeginInit();
flipped_bitmap.Source = bitmap;
flipped_bitmap.Transform = new ScaleTransform { ScaleY = -1 };
flipped_bitmap.EndInit();
bitmap = flipped_bitmap;
}
bitmap.Freeze();
return new ImageData (bitmap, info);
}
}
}
public override void Write (Stream file, ImageData image)
{
throw new NotImplementedException ("Hg3Format.Write not implemented");
}
class Decoder
{
byte[] m_in1;
byte[] m_in2;
byte[] m_image;
uint m_in1_size;
uint m_in2_size;
uint m_dst_size;
uint m_width;
uint m_height;
public byte[] Data { get { return m_image; } }
public Decoder (byte[] in1, uint in1_size, byte[] in2, uint in2_size,
uint width, uint height)
{
m_in1 = in1;
m_in1_size = in1_size;
m_in2 = in2;
m_in2_size = in2_size;
m_width = width;
m_height = height;
m_dst_size = width*height*4;
m_image = new byte[(int)m_dst_size];
}
uint esi;
uint edi;
uint eax;
uint ebx;
uint ecx;
uint edx;
uint L0, L1, L2, L3, L4;
uint m_plane;
public void Unpack ()
{
m_plane = 0;
edi = 0;
esi = 0;
ebx = 0;
eax = m_in1_size;
L0 = m_in2_size;
L1 = 0;
bool skip_first = GetNextBit();
Proc4();
ecx = m_dst_size;
if (eax > m_dst_size)
throw new InvalidFormatException ("Underflow at Hg3Format.Decoder.Unpack()");
m_dst_size -= eax;
ecx >>= 2;
L2 = eax;
L3 = ecx;
L4 = ecx;
for (;;)
{
if (!skip_first)
{
// @@1:
if (0 == L2)
break;
Proc4();
ecx = eax;
if (ecx > L2)
throw new InvalidFormatException ("Overflow at Hg3Format.Decoder.Unpack()");
L2 -= ecx;
eax = 0;
do
Proc2();
while (0 != --ecx);
}
// @@1a:
if (0 == L2)
break;
Proc4();
ecx = eax;
if (ecx > L2 || ecx > L0)
throw new InvalidFormatException ("Overflow (2) at Hg3Format.Decoder.Unpack()");
L2 -= ecx;
L0 -= ecx;
do
{
eax = m_in2[L1++];
Proc2();
}
while (0 != --ecx);
skip_first = false;
}
// @@7:
ecx = m_dst_size;
esi = 0;
if (0 != ecx)
{
eax = 0;
do
Proc2();
while (0 != --ecx);
}
Proc6 (m_width, m_height);
// @@9:
eax = 0;
edx = m_in1_size;
}
void Proc2 () // @@2
{
m_image[edi] = (byte)eax;
edi += 4;
if (0 == --L3)
{
edi = ++m_plane;
L3 = L4;
}
}
bool GetNextBit () // @@3
{
bool carry = 0 != (ebx & 1);
ebx >>= 1;
if (0 == ebx)
{
if (0 == m_in1_size--)
throw new InvalidFormatException ("Hg3Format.Decoder.Underflow at GetNextBit()");
ebx = (uint)(m_in1[esi++] | 0x100);
carry = 0 != (ebx & 1);
ebx >>= 1;
}
return carry;
}
void Proc4 () // @@4
{
ecx = 0;
eax = 0;
do
{
if (ecx >= 0x20)
throw new InvalidFormatException ("Hg3Format.Decoder.Overflow at Proc4");
++ecx;
}
while (!GetNextBit());
++eax;
while (0 != --ecx)
{
eax += eax + (uint)(GetNextBit() ? 1 : 0);
}
}
void Proc6 (uint width, uint height)
{
uint[] table = new uint[0x100];
ecx = 0;
for (uint i = 0; i < 0x100; ++i)
{
eax = 0xffffffff;
edx = i;
do
{
eax >>= 2;
eax |= (edx & 3) << 30;
eax >>= 6;
edx >>= 2;
}
while (0 != (0x80 & eax));
table[i] = eax;
}
ecx = width * height * 4;
for (uint i = 0; i < ecx; i += 4)
{
eax = m_image[i];
edx = table[eax];
edx <<= 2;
eax = m_image[i+1];
edx += table[eax];
edx <<= 2;
eax = m_image[i+2];
edx += table[eax];
edx <<= 2;
eax = m_image[i+3];
edx += table[eax];
m_image[i] = (byte)(edx);
m_image[i+1] = (byte)(edx >> 8);
m_image[i+2] = (byte)(edx >> 16);
m_image[i+3] = (byte)(edx >> 24);
}
edi = 0;
for (int i = 0; i < 4; ++i)
{
eax = m_image[edi];
edx = (uint)(0 == (eax & 1) ? 0 : 0xff);
eax >>= 1;
eax ^= edx;
m_image[edi++] = (byte)eax;
}
ecx = width;
if (0 != --ecx)
{
ecx <<= 2;
do
{
eax = m_image[edi];
edx = (uint)(0 == (eax & 1) ? 0 : 0xff);
eax >>= 1;
eax ^= edx;
eax += m_image[edi-4];
m_image[edi++] = (byte)eax;
}
while (0 != --ecx);
}
ecx = height;
if (0 != --ecx)
{
uint stride = width*4;
ecx *= stride;
do
{
eax = m_image[edi];
edx = (uint)(0 == (eax & 1) ? 0 : 0xff);
eax >>= 1;
eax ^= edx;
eax += m_image[edi-stride];
m_image[edi++] = (byte)eax;
}
while (0 != --ecx);
}
}
}
}
}

1006
ArcFormats/ImageTLG.cs Normal file

File diff suppressed because it is too large Load Diff

477
ArcFormats/ImageWCG.cs Normal file
View File

@ -0,0 +1,477 @@
//! \file ImageWCG.cs
//! \date Sat Jul 19 23:07:32 2014
//! \brief Liar-soft WCG image format implementation.
//
using System;
using System.IO;
using System.ComponentModel.Composition;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Collections.Generic;
using System.Text;
namespace GameRes.Formats
{
[Export(typeof(ImageFormat))]
public class WcgFormat : ImageFormat
{
public override string Tag { get { return "WCG"; } }
public override string Description { get { return "Liar-soft proprietary image format"; } }
public override uint Signature { get { return 0x02714757; } }
public override ImageMetaData ReadMetaData (Stream stream)
{
if (0x57 != stream.ReadByte() || 0x47 != stream.ReadByte())
return null;
using (var file = new BinaryReader (stream, Encoding.ASCII, true))
{
uint flags = file.ReadUInt16();
if (1 != (flags & 0x0f) || 0x20 != file.ReadByte() || 0 != file.ReadByte())
return null;
var meta = new ImageMetaData();
file.BaseStream.Position = 8;
meta.Width = file.ReadUInt32();
meta.Height = file.ReadUInt32();
meta.BPP = 32;
return meta;
}
}
public override ImageData Read (Stream file, ImageMetaData info)
{
uint pixel_size = info.Width * info.Height;
using (var reader = new Reader (file, pixel_size))
{
reader.Unpack();
byte[] pixels = reader.Data;
var bitmap = BitmapSource.Create ((int)info.Width, (int)info.Height, 96, 96,
PixelFormats.Bgra32, null, pixels, (int)info.Width*4);
bitmap.Freeze();
return new ImageData (bitmap, info);
}
}
public override void Write (Stream file, ImageData image)
{
Stream stream = file;
bool buffer_used = false;
if (!stream.CanSeek)
{
stream = new MemoryStream();
buffer_used = true;
}
try
{
using (var writer = new Writer (stream, image.Bitmap))
{
writer.Pack();
}
if (buffer_used)
{
stream.Position = 0;
stream.CopyTo (file);
}
}
finally
{
if (buffer_used)
stream.Dispose();
}
}
private class Reader : IDisposable
{
private byte[] m_data;
private BinaryReader m_input;
private uint m_input_size;
private ushort[] m_index;
private uint m_next_ptr;
private uint m_next_size;
private uint m_src;
private uint m_src_size;
private uint m_dst_size;
private uint esi;
private uint edi;
private uint m_index_length_limit;
private int m_bits;
public byte[] Data { get { return m_data; } }
public Reader (Stream file, uint pixel_size)
{
m_data = new byte[pixel_size*4];
m_input_size = (uint)file.Length;
m_input = new BinaryReader (file, Encoding.ASCII, true);
}
public void Unpack ()
{
m_next_ptr = 16;
m_next_size = m_input_size-16;
if (Unpack (2))
Unpack (0);
for (uint i = 3; i < m_data.Length; i += 4)
m_data[i] = (byte)~m_data[i];
}
private bool Unpack (uint offset)
{
m_src = m_next_ptr;
m_src_size = m_next_size;
m_dst_size = (uint)(m_data.Length / 4);
if (m_src_size < 12)
throw new InvalidFormatException ("Invalid file size");
m_src_size -= 12;
m_input.BaseStream.Position = m_next_ptr;
uint unpacked_size = m_input.ReadUInt32();
uint data_size = m_input.ReadUInt32();
uint index_size = m_input.ReadUInt16(); // 8
if (unpacked_size != m_dst_size*2)
throw new InvalidFormatException ("Invalid image size");
if (0 == index_size || index_size*2 > m_src_size)
throw new InvalidFormatException ("Invalid palette size");
m_src_size -= index_size*2;
if (data_size > m_src_size)
throw new InvalidFormatException ("Invalid compressed data size");
esi = m_src + index_size*2 + 12;
edi = offset;
m_next_size = m_src_size - data_size;
m_next_ptr = esi + data_size;
m_src_size = data_size;
return DecodeStream (index_size);
}
void ReadIndex (uint index_size)
{
m_input.BaseStream.Position = m_src+12;
m_index = new ushort[index_size];
for (int i = 0; i < index_size; ++i)
m_index[i] = m_input.ReadUInt16();
}
bool DecodeStream (uint index_size)
{
ReadIndex (index_size);
m_input.BaseStream.Position = esi;
bool small_index = index_size < 0x1002;
m_index_length_limit = small_index ? 0x06u : 0x0eu;
uint index_bit_length = small_index ? 3u : 4u;
m_bits = 0;
while (m_dst_size > 0)
{
uint dst_count = 1;
uint index_length = GetBits (index_bit_length, 0);
if (0 == index_length)
{
dst_count = GetBits (4, 0) + 2;
index_length = GetBits (index_bit_length, 0);
}
if (0 == index_length)
return false; // std::cerr << "zero index length\n";
uint index = GetIndex (index_length);
if (index >= index_size)
return false; // std::cerr << "invalid index\n";
if (dst_count > m_dst_size)
return false;
m_dst_size -= dst_count;
ushort word = m_index[index];
do {
PutWord (word); // *(uint16_t*)edi = word;
edi += 4;
} while (0 != --dst_count);
}
return true;
}
void PutWord (ushort word)
{
m_data[edi ] = (byte)(word & 0xff);
m_data[edi+1] = (byte)(word >> 8);
}
bool GetNextBit ()
{
bool carry = 0 != (m_bits & 0x80);
m_bits <<= 1;
if (0 == (m_bits & 0xff))
{
if (0 == m_src_size--)
throw new InvalidFormatException ("Unexpected end of file");
m_bits = (int)m_input.ReadByte();
esi++;
m_bits = (m_bits << 1) + 1;
carry = 0 != (m_bits & 0x100);
}
return carry;
}
uint GetIndex (uint count)
{
if (0 == --count)
return GetNextBit() ? 1u : 0u;
if (count < m_index_length_limit)
return GetBits (count, 1);
while (GetNextBit())
{
if (count >= 0x10)
throw new InvalidFormatException ("Invalid index count");
++count;
}
return GetBits (count, 1);
}
uint GetBits (uint count, uint word)
{
do
{
bool carry = GetNextBit();
word = (word << 1) + (carry ? 1u : 0u);
}
while (0 != --count);
return word;
}
#region IDisposable Members
bool disposed = false;
public void Dispose ()
{
Dispose (true);
GC.SuppressFinalize (this);
}
protected virtual void Dispose (bool disposing)
{
if (!disposed)
{
if (disposing)
m_input.Dispose();
m_input = null;
m_data = null;
m_index = null;
disposed = true;
}
}
#endregion
}
private class Writer : IDisposable
{
private BinaryWriter m_out;
private uint m_width;
private uint m_height;
private uint m_pixels;
private byte[] m_data;
Dictionary<ushort, ushort> m_index = new Dictionary<ushort, ushort>();
private uint m_base_length;
private uint m_base_index_length;
private int m_bits;
public Writer (Stream stream, BitmapSource bitmap)
{
m_width = (uint)bitmap.PixelWidth;
m_height = (uint)bitmap.PixelHeight;
m_pixels = m_width*m_height;
if (bitmap.Format != PixelFormats.Bgra32)
{
var converted_bitmap = new FormatConvertedBitmap();
converted_bitmap.BeginInit();
converted_bitmap.Source = bitmap;
converted_bitmap.DestinationFormat = PixelFormats.Bgra32;
converted_bitmap.EndInit();
bitmap = converted_bitmap;
}
m_data = new byte[m_pixels*4];
bitmap.CopyPixels (m_data, bitmap.PixelWidth*4, 0);
m_out = new BinaryWriter (stream, Encoding.ASCII, true);
}
public void Pack ()
{
byte[] header = { (byte)'W', (byte)'G', 0x71, 2, 0x20, 0, 0, 0x40 };
m_out.Write (header, 0, header.Length);
m_out.Write (m_width);
m_out.Write (m_height);
Pack (1, 0xff00);
Pack (0, 0);
}
ushort GetWord (int offset)
{
return (ushort)(m_data[offset*2] | m_data[offset*2+1] << 8);
}
private void Pack (int data, ushort mask)
{
var header_pos = m_out.Seek (0, SeekOrigin.Current);
m_out.Seek (12, SeekOrigin.Current);
BuildIndex (data, mask);
bool small_index = m_index.Count < 0x1002;
m_base_length = small_index ? 3u : 4u;
m_base_index_length = small_index ? 7u : 15u;
m_bits = 1;
// encode
for (uint i = 0; i < m_pixels;)
{
ushort word = GetWord (data);
data += 2;
++i;
ushort color = m_index[(ushort)(word^mask)];
uint count = 1;
while (i < m_pixels)
{
if (word != GetWord (data))
break;
++count;
data += 2;
++i;
if (0x11 == count)
break;
}
if (count > 1)
{
PutBits (m_base_length, 0);
PutBits (4, count-2);
}
PutIndex (color);
}
Flush();
var end_pos = m_out.Seek (0, SeekOrigin.Current);
uint data_size = (uint)(end_pos - header_pos - 12 - m_index.Count*2);
m_out.Seek ((int)header_pos, SeekOrigin.Begin);
m_out.Write (m_pixels*2u);
m_out.Write (data_size);
m_out.Write ((ushort)m_index.Count);
m_out.Write ((ushort)(small_index ? 7 : 14)); // 0x0e
m_out.Seek ((int)end_pos, SeekOrigin.Begin);
}
void BuildIndex (int data, ushort mask)
{
m_index.Clear();
uint[] freq_table = new uint[65536];
for (var data_end = data + m_pixels*2; data < data_end; data += 2)
freq_table[GetWord (data)^mask]++;
var index = new List<ushort>();
for (int i = 0; i < freq_table.Length; ++i)
{
if (0 != freq_table[i])
index.Add ((ushort)i);
}
index.Sort ((a, b) => freq_table[a] < freq_table[b] ? 1 : freq_table[a] == freq_table[b] ? 0 : -1);
ushort j = 0;
foreach (var color in index)
{
m_out.Write (color);
m_index.Add (color, j++);
}
}
void Flush ()
{
if (1 != m_bits)
{
do
m_bits <<= 1;
while (0 == (m_bits & 0x100));
m_out.Write ((byte)(m_bits & 0xff));
m_bits = 1;
}
}
void PutBit (bool bit)
{
m_bits <<= 1;
m_bits |= bit ? 1 : 0;
if (0 != (m_bits & 0x100))
{
m_out.Write ((byte)(m_bits & 0xff));
m_bits = 1;
}
}
void PutBits (uint length, uint x)
{
x <<= (int)(32-length);
while (0 != length--)
{
PutBit (0 != (x & 0x80000000));
x <<= 1;
}
}
static uint GetBitsLength (ushort val)
{
uint length = 0;
do
{
++length;
val >>= 1;
}
while (0 != val);
return length;
}
void PutIndex (ushort index)
{
uint length = GetBitsLength (index);
if (length < m_base_index_length)
{
PutBits (m_base_length, length);
if (1 == length)
PutBit (index != 0);
else
PutBits (length-1, index);
}
else
{
PutBits (m_base_length, m_base_index_length);
for (uint i = m_base_index_length; i < length; ++i)
PutBit (true);
PutBit (false);
PutBits (length-1, index);
}
}
#region IDisposable Members
bool disposed = false;
public void Dispose ()
{
Dispose (true);
GC.SuppressFinalize (this);
}
protected virtual void Dispose (bool disposing)
{
if (!disposed)
{
if (disposing)
m_out.Dispose();
m_out = null;
m_data = null;
m_index = null;
disposed = true;
}
}
#endregion
}
}
}

View File

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("ArcFormats")]
[assembly: AssemblyDescription("Visual Novel resources library")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ArcFormats")]
[assembly: AssemblyCopyright("Copyright © 2014 mørkt")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("b9f45cc0-a966-4ccb-ac73-e99ee087567a")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// 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.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@ -0,0 +1,73 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.18444
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace GameRes.Formats.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "12.0.0.0")]
public sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
return defaultInstance;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("NotEncrypted")]
public global::GameRes.Formats.NpaTitleId NPAScheme {
get {
return ((global::GameRes.Formats.NpaTitleId)(this["NPAScheme"]));
}
set {
this["NPAScheme"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
public string XP3Scheme {
get {
return ((string)(this["XP3Scheme"]));
}
set {
this["XP3Scheme"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("4294967295")]
public uint YPFKey {
get {
return ((uint)(this["YPFKey"]));
}
set {
this["YPFKey"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public global::GameRes.Formats.IntEncryptionInfo INTEncryption {
get {
return ((global::GameRes.Formats.IntEncryptionInfo)(this["INTEncryption"]));
}
set {
this["INTEncryption"] = value;
}
}
}
}

View File

@ -0,0 +1,18 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="GameRes.Formats.Properties" GeneratedClassName="Settings">
<Profiles />
<Settings>
<Setting Name="NPAScheme" Type="GameRes.Formats.NpaTitleId" Scope="User">
<Value Profile="(Default)">NotEncrypted</Value>
</Setting>
<Setting Name="XP3Scheme" Type="System.String" Scope="User">
<Value Profile="(Default)" />
</Setting>
<Setting Name="YPFKey" Type="System.UInt32" Scope="User">
<Value Profile="(Default)">4294967295</Value>
</Setting>
<Setting Name="INTEncryption" Type="GameRes.Formats.IntEncryptionInfo" Scope="User">
<Value Profile="(Default)" />
</Setting>
</Settings>
</SettingsFile>

36
ArcFormats/Settings.cs Normal file
View File

@ -0,0 +1,36 @@
namespace GameRes.Formats.Properties {
// This class allows you to handle specific events on the settings class:
// The SettingChanging event is raised before a setting's value is changed.
// The PropertyChanged event is raised after a setting's value is changed.
// The SettingsLoaded event is raised after the setting values are loaded.
// The SettingsSaving event is raised before the setting values are saved.
public sealed partial class Settings {
public Settings() {
// // To add event handlers for saving and changing settings, uncomment the lines below:
//
// this.SettingChanging += this.SettingChangingEventHandler;
//
// this.SettingsSaving += this.SettingsSavingEventHandler;
//
if (null != System.Windows.Application.Current)
System.Windows.Application.Current.Exit += ApplicationExitHandler;
}
void ApplicationExitHandler (object sender, System.Windows.ExitEventArgs args)
{
Default.Save();
}
private void SettingChangingEventHandler(object sender, System.Configuration.SettingChangingEventArgs e) {
// Add code to handle the SettingChangingEvent event here.
}
private void SettingsSavingEventHandler(object sender, System.ComponentModel.CancelEventArgs e) {
// Add code to handle the SettingsSaving event here.
}
}
}

139
ArcFormats/Strings/arcStrings.Designer.cs generated Normal file
View File

@ -0,0 +1,139 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.18444
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace GameRes.Formats.Strings {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
public class arcStrings {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal arcStrings() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("GameRes.Formats.Strings.arcStrings", typeof(arcStrings).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized string similar to Archive content is encrypted.
///Choose appropriate encryption scheme..
/// </summary>
public static string ArcEncryptedNotice {
get {
return ResourceManager.GetString("ArcEncryptedNotice", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to no encryption.
/// </summary>
public static string ArcNoEncryption {
get {
return ResourceManager.GetString("ArcNoEncryption", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Numeric key.
/// </summary>
public static string INTLabelNumericKey {
get {
return ResourceManager.GetString("INTLabelNumericKey", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Passphrase.
/// </summary>
public static string INTLabelPassphrase {
get {
return ResourceManager.GetString("INTLabelPassphrase", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Scheme.
/// </summary>
public static string INTLabelScheme {
get {
return ResourceManager.GetString("INTLabelScheme", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Archive directory is encrypted.
///Enter archive encryption key or choose
///predefined encryption scheme..
/// </summary>
public static string INTNotice {
get {
return ResourceManager.GetString("INTNotice", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to 8-bit encryption key.
/// </summary>
public static string YPFLabelKey {
get {
return ResourceManager.GetString("YPFLabelKey", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Archive directory is encrypted.
///Enter archive encryption key..
/// </summary>
public static string YPFNotice {
get {
return ResourceManager.GetString("YPFNotice", resourceCulture);
}
}
}
}

View File

@ -0,0 +1,148 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="ArcEncryptedNotice" xml:space="preserve">
<value>Archive content is encrypted.
Choose appropriate encryption scheme.</value>
</data>
<data name="ArcNoEncryption" xml:space="preserve">
<value>no encryption</value>
</data>
<data name="INTLabelNumericKey" xml:space="preserve">
<value>Numeric key</value>
</data>
<data name="INTLabelPassphrase" xml:space="preserve">
<value>Passphrase</value>
</data>
<data name="INTLabelScheme" xml:space="preserve">
<value>Scheme</value>
</data>
<data name="INTNotice" xml:space="preserve">
<value>Archive directory is encrypted.
Enter archive encryption key or choose
predefined encryption scheme.</value>
</data>
<data name="YPFLabelKey" xml:space="preserve">
<value>8-bit encryption key</value>
</data>
<data name="YPFNotice" xml:space="preserve">
<value>Archive directory is encrypted.
Enter archive encryption key.</value>
</data>
</root>

View File

@ -0,0 +1,148 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="ArcEncryptedNotice" xml:space="preserve">
<value>Содержимое архива зашифровано.
Выберите алгоритм шифрования.</value>
</data>
<data name="ArcNoEncryption" xml:space="preserve">
<value>без шифрования</value>
</data>
<data name="INTLabelNumericKey" xml:space="preserve">
<value>Цифровой ключ</value>
</data>
<data name="INTLabelPassphrase" xml:space="preserve">
<value>Пароль</value>
</data>
<data name="INTLabelScheme" xml:space="preserve">
<value>Вариант</value>
</data>
<data name="INTNotice" xml:space="preserve">
<value>Заголовок архива зашифрован.
Введите ключ шифрования или выберите
один из предопределённых вариантов.</value>
</data>
<data name="YPFLabelKey" xml:space="preserve">
<value>8-битный ключ шифрования</value>
</data>
<data name="YPFNotice" xml:space="preserve">
<value>Заголовок архива зашифрован.
Введите ключ шифрования.</value>
</data>
</root>

57
ArcFormats/WidgetINT.xaml Normal file
View File

@ -0,0 +1,57 @@
<Grid x:Class="GameRes.Formats.GUI.WidgetINT"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="clr-namespace:GameRes.Formats.Strings"
xmlns:local="clr-namespace:GameRes.Formats.GUI"
MaxWidth="250">
<Grid.Resources>
<local:KeyConverter x:Key="keyConverter"/>
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip"
Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>
</Style.Triggers>
</Style>
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition MinWidth="100" Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Label Content="{x:Static s:arcStrings.INTLabelNumericKey}" Target="{Binding ElementName=Passkey}"
Grid.Column="0" Grid.Row="0" HorizontalAlignment="Right"/>
<TextBox Name="Passkey" Grid.Column="1" Grid.Row="0" Margin="0,3,0,3">
<TextBox.Text>
<Binding Path="Key" Converter="{StaticResource keyConverter}" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<local:PasskeyRule/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
<Validation.ErrorTemplate>
<ControlTemplate>
<DockPanel>
<TextBlock DockPanel.Dock="Right" Foreground="Red" FontWeight="Bold" Text="!" VerticalAlignment="Center"/>
<Border BorderBrush="Red" BorderThickness="1">
<AdornedElementPlaceholder Name="ValidationAdorner" />
</Border>
</DockPanel>
</ControlTemplate>
</Validation.ErrorTemplate>
</TextBox>
<Label Content="{x:Static s:arcStrings.INTLabelPassphrase}" Target="{Binding ElementName=Passphrase}"
Grid.Column="0" Grid.Row="1" HorizontalAlignment="Right"/>
<TextBox Name="Passphrase" Grid.Column="1" Grid.Row="1" Margin="0,3,0,3"
Text="{Binding Path=Password}"/>
<Label Content="{x:Static s:arcStrings.INTLabelScheme}" Target="{Binding ElementName=EncScheme}"
Grid.Column="0" Grid.Row="2" HorizontalAlignment="Right"/>
<ComboBox Name="EncScheme" Grid.Column="1" Grid.Row="2" Margin="0,3,0,0"
Width="{Binding ElementName=Passkey, Path=ActualWidth}"
SelectedValue="{Binding Path=Scheme}"/>
</Grid>

View File

@ -0,0 +1,126 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace GameRes.Formats.GUI
{
/// <summary>
/// Interaction logic for WidgetINT.xaml
/// </summary>
public partial class WidgetINT : Grid
{
public WidgetINT (IntEncryptionInfo encryption_info)
{
InitializeComponent();
this.DataContext = encryption_info;
EncScheme.ItemsSource = IntOpener.KnownSchemes.Keys;
Passphrase.TextChanged += OnPassphraseChanged;
EncScheme.SelectionChanged += OnSchemeChanged;
}
public IntEncryptionInfo Info { get { return this.DataContext as IntEncryptionInfo; } }
void OnPasskeyChanged (object sender, TextChangedEventArgs e)
{
}
void OnPassphraseChanged (object sender, TextChangedEventArgs e)
{
var widget = sender as TextBox;
uint key = IntOpener.EncodePassPhrase (widget.Text);
Passkey.Text = key.ToString ("X8");
}
void OnSchemeChanged (object sender, SelectionChangedEventArgs e)
{
var widget = sender as ComboBox;
IntOpener.KeyData keydata;
if (IntOpener.KnownSchemes.TryGetValue (widget.SelectedItem as string, out keydata))
{
Passphrase.TextChanged -= OnPassphraseChanged;
try
{
Passphrase.Text = keydata.Passphrase;
Passkey.Text = keydata.Key.ToString ("X8");
}
finally
{
Passphrase.TextChanged += OnPassphraseChanged;
}
}
}
public uint? GetKey ()
{
if (null != Info.Key && Info.Key.HasValue)
return Info.Key;
if (!string.IsNullOrEmpty (Info.Scheme))
{
IntOpener.KeyData keydata;
if (IntOpener.KnownSchemes.TryGetValue (Info.Scheme, out keydata))
return keydata.Key;
}
if (!string.IsNullOrEmpty (Info.Password))
return IntOpener.EncodePassPhrase (Info.Password);
return null;
}
}
[ValueConversion(typeof(uint?), typeof(string))]
public class KeyConverter : IValueConverter
{
public object Convert (object value, Type targetType, object parameter, CultureInfo culture)
{
uint? key = (uint?)value;
return null != key ? key.Value.ToString ("X") : "";
}
public object ConvertBack (object value, Type targetType, object parameter, CultureInfo culture)
{
string strValue = value as string;
uint result_key;
if (uint.TryParse(strValue, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out result_key))
return new uint? (result_key);
else
return null;
}
}
public class PasskeyRule : ValidationRule
{
public PasskeyRule()
{
}
public override ValidationResult Validate (object value, CultureInfo cultureInfo)
{
uint key = 0;
try
{
if (((string)value).Length > 0)
key = UInt32.Parse ((string)value, NumberStyles.HexNumber);
}
catch
{
return new ValidationResult (false, "Numeric key should be a 32-bit hexadecimal integer");
}
return new ValidationResult (true, null);
}
}
}

View File

@ -0,0 +1,6 @@
<Grid x:Class="GameRes.Formats.GUI.WidgetNPA"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
MaxWidth="250">
<ComboBox Name="Scheme" Margin="5" Width="180"/>
</Grid>

View File

@ -0,0 +1,23 @@
using System.Windows;
using System.Windows.Controls;
namespace GameRes.Formats.GUI
{
/// <summary>
/// Interaction logic for WidgetNPA.xaml
/// </summary>
public partial class WidgetNPA : Grid
{
public WidgetNPA (string scheme)
{
InitializeComponent();
Scheme.ItemsSource = NpaOpener.KnownSchemes;
Scheme.SelectedItem = scheme;
}
public string GetScheme()
{
return Scheme.SelectedItem as string;
}
}
}

View File

@ -0,0 +1,6 @@
<Grid x:Class="GameRes.Formats.GUI.WidgetXP3"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
MaxWidth="250">
<ComboBox Name="Scheme" Margin="5" Width="180"/>
</Grid>

View File

@ -0,0 +1,24 @@
using System.Windows;
using System.Windows.Controls;
using GameRes.Formats.KiriKiri;
namespace GameRes.Formats.GUI
{
/// <summary>
/// Interaction logic for WidgetXP3.xaml
/// </summary>
public partial class WidgetXP3 : Grid
{
public WidgetXP3 (string scheme)
{
InitializeComponent();
Scheme.ItemsSource = Xp3Opener.KnownSchemes.Keys;
Scheme.SelectedItem = scheme;
}
public string GetScheme ()
{
return Scheme.SelectedItem as string;
}
}
}

12
ArcFormats/WidgetYPF.xaml Normal file
View File

@ -0,0 +1,12 @@
<Grid x:Class="GameRes.Formats.GUI.WidgetYPF"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="clr-namespace:GameRes.Formats.Strings"
MaxWidth="250">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition MinWidth="100" Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{x:Static s:arcStrings.YPFLabelKey}" Target="{Binding ElementName=Passkey}" Grid.Column="0" Grid.Row="0" HorizontalAlignment="Right"/>
<TextBox Name="Passkey" Margin="5" Width="100" Grid.Column="1" Grid.Row="0"/>
</Grid>

View File

@ -0,0 +1,29 @@
using System.Windows;
using System.Windows.Controls;
namespace GameRes.Formats.GUI
{
/// <summary>
/// Interaction logic for WidgetYPF.xaml
/// </summary>
public partial class WidgetYPF : Grid
{
public WidgetYPF (uint? key)
{
InitializeComponent();
if (null != key)
this.Passkey.Text = key.Value.ToString();
else
this.Passkey.Text = null;
}
public uint? GetKey ()
{
uint key;
if (uint.TryParse (this.Passkey.Text, out key))
return key;
else
return null;
}
}
}

21
ArcFormats/app.config Normal file
View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="GameRes.Formats.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
</sectionGroup>
</configSections>
<userSettings>
<GameRes.Formats.Properties.Settings>
<setting name="NPAScheme" serializeAs="String">
<value>NotEncrypted</value>
</setting>
<setting name="XP3Scheme" serializeAs="String">
<value />
</setting>
<setting name="YPFKey" serializeAs="String">
<value>4294967295</value>
</setting>
</GameRes.Formats.Properties.Settings>
</userSettings>
</configuration>

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="BouncyCastle" version="1.7.0" targetFramework="net45" />
</packages>

24
ArcParameters.xaml Normal file
View File

@ -0,0 +1,24 @@
<Window x:Class="GARbro.GUI.ArcParametersDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="clr-namespace:GARbro.GUI.Strings"
xmlns:local="clr-namespace:GARbro.GUI"
Title="{x:Static s:guiStrings.TextParametersTitle}" SizeToContent="WidthAndHeight"
UseLayoutRounding="True" Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"
ShowInTaskbar="False" WindowStartupLocation="CenterOwner" ResizeMode="NoResize">
<Window.Resources>
<BitmapImage x:Key="Icon64x64Info" UriSource="Images/64x64/info.png"/>
</Window.Resources>
<StackPanel Orientation="Horizontal">
<Image Width="64" Height="64" Source="Images/64x64/info.png"
SnapsToDevicePixels="True" VerticalAlignment="Top"
RenderOptions.BitmapScalingMode="HighQuality" Margin="10,10,0,0"/>
<DockPanel Name="WidgetPane" VerticalAlignment="Top" Margin="10">
<TextBlock Name="Notice" DockPanel.Dock="Top" TextWrapping="WrapWithOverflow" Margin="0,0,0,10"/>
<StackPanel DockPanel.Dock="Bottom" HorizontalAlignment="Right" Orientation="Horizontal" Margin="20,20,0,0">
<Button Content="Ok" Click="Button_Click" IsDefault="True" Width="70" Margin="0,0,10,0"/>
<Button Content="Cancel" IsCancel="True" Width="70" Margin="10,0,0,0"/>
</StackPanel>
</DockPanel>
</StackPanel>
</Window>

22
ArcParameters.xaml.cs Normal file
View File

@ -0,0 +1,22 @@
using System.Windows;
namespace GARbro.GUI
{
/// <summary>
/// Interaction logic for ArcParameters.xaml
/// </summary>
public partial class ArcParametersDialog : Window
{
public ArcParametersDialog (UIElement widget, string notice)
{
InitializeComponent();
this.WidgetPane.Children.Add (widget);
this.Notice.Text = notice;
}
private void Button_Click (object sender, RoutedEventArgs e)
{
DialogResult = true;
}
}
}

6
Console/App.config Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.1"/>
</startup>
</configuration>

137
Console/ConsoleBrowser.cs Normal file
View File

@ -0,0 +1,137 @@
//! \file Program.cs
//! \date Mon Jun 30 20:12:13 2014
//! \brief game resources browser.
//
using System;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Text;
using System.Linq;
using System.Collections.Generic;
using System.Diagnostics;
using GameRes;
namespace GARbro
{
class ConsoleBrowser
{
private string m_arc_name;
void ListFormats ()
{
Console.WriteLine ("Recognized resource formats:");
foreach (var impl in FormatCatalog.Instance.ArcFormats)
{
Console.WriteLine ("{0,-4} {1}", impl.Tag, impl.Description);
}
}
void ExtractAll (ArcFile arc)
{
arc.ExtractFiles ((i, entry) => {
Console.WriteLine ("Extracting {0} ...", entry.Name);
return ExtractAction.Continue;
});
}
void ExtractFile (ArcFile arc, string name)
{
Entry entry = arc.Dir.FirstOrDefault (e => e.Name.Equals (name, StringComparison.OrdinalIgnoreCase));
if (null == entry)
{
Console.Error.WriteLine ("'{0}' not found within {1}", name, m_arc_name);
return;
}
Console.WriteLine ("Extracting {0} ...", entry.Name);
arc.Extract (entry);
}
void TestArc (string[] args)
{
/*
if (args.Length > 1)
{
uint pass = GameRes.Formats.IntOpener.EncodePassPhrase (args[1]);
Console.WriteLine ("{0:X8}", pass);
}
*/
}
void Run (string[] args)
{
int argn = 0;
if (args[argn].Equals ("-l"))
{
ListFormats();
return;
}
if (args[argn].Equals ("-t"))
{
TestArc (args);
return;
}
if (args[argn].Equals ("-x"))
{
++argn;
if (args.Length < 2)
{
Usage();
return;
}
}
m_arc_name = args[argn];
var arc = ArcFile.TryOpen (m_arc_name);
if (null == arc)
{
Console.Error.WriteLine ("{0}: unknown format", m_arc_name);
return;
}
using (arc)
{
if (args.Length > argn+1)
{
for (int i = argn+1; i < args.Length; ++i)
ExtractFile (arc, args[i]);
}
else if (args[0].Equals ("-x"))
{
ExtractAll (arc);
}
else
{
foreach (var entry in arc.Dir)
{
Console.WriteLine ("{0,9} {1}", entry.Size, entry.Name);
}
}
}
}
static void Usage ()
{
Console.WriteLine ("Usage: gameres [OPTIONS] ARC [ENTRIES]");
Console.WriteLine (" -l list recognized archive formats");
Console.WriteLine (" -x extract all files");
Console.WriteLine ("Without options displays contents of specified archive.");
}
static void Main (string[] args)
{
if (0 == args.Length)
{
Usage();
return;
}
var listener = new TextWriterTraceListener (Console.Error);
Trace.Listeners.Add(listener);
try
{
var browser = new ConsoleBrowser();
browser.Run (args);
}
catch (Exception X)
{
Console.Error.WriteLine (X.Message);
}
}
}
}

View File

@ -0,0 +1,101 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{B966F292-431A-4D8A-A1D3-1EB45048A1D2}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>GARbro</RootNamespace>
<AssemblyName>GARbro.Console</AssemblyName>
<TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
<UpdateEnabled>false</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
<UpdateInterval>7</UpdateInterval>
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
<UpdatePeriodically>false</UpdatePeriodically>
<UpdateRequired>false</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<IsWebBootstrapper>false</IsWebBootstrapper>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="ConsoleBrowser.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config">
<SubType>Designer</SubType>
</None>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\GameRes\GameRes.csproj">
<Project>{453c087f-e416-4ae9-8c03-d8760da0574b}</Project>
<Name>GameRes</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include=".NETFramework,Version=v4.5">
<Visible>False</Visible>
<ProductName>Microsoft .NET Framework 4.5 %28x86 and x64%29</ProductName>
<Install>true</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
<Install>false</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1</ProductName>
<Install>false</Install>
</BootstrapperPackage>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<PublishUrlHistory>publish\</PublishUrlHistory>
<InstallUrlHistory />
<SupportUrlHistory />
<UpdateUrlHistory />
<BootstrapperUrlHistory />
<ErrorReportUrlHistory />
<FallbackCulture>en-US</FallbackCulture>
<VerifyUploadedFiles>false</VerifyUploadedFiles>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'">
<StartArguments>-l</StartArguments>
</PropertyGroup>
</Project>

View File

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("GARbro.Console")]
[assembly: AssemblyDescription("Game Archive browser")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("GARbro")]
[assembly: AssemblyCopyright("Copyright © 2014 mørkt")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("a0e89f40-24ea-4958-a80c-d4f7b1386c91")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// 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.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

166
DragScroll.cs Normal file
View File

@ -0,0 +1,166 @@
//! \file DragScroll.cs
//! \date Sun Jul 06 10:47:20 2014
//! \brief Scroll control contents by dragging.
//
// http://matthamilton.net/touchscrolling-for-scrollviewer
using System.Collections.Generic;
using System.Windows.Controls;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Diagnostics;
namespace GARbro.GUI
{
public class TouchScrolling : DependencyObject
{
public static bool GetIsEnabled(DependencyObject obj)
{
return (bool)obj.GetValue(IsEnabledProperty);
}
public static void SetIsEnabled(DependencyObject obj, bool value)
{
obj.SetValue(IsEnabledProperty, value);
}
public bool IsEnabled
{
get { return (bool)GetValue(IsEnabledProperty); }
set { SetValue(IsEnabledProperty, value); }
}
public static readonly DependencyProperty IsEnabledProperty =
DependencyProperty.RegisterAttached("IsEnabled", typeof(bool), typeof(TouchScrolling), new UIPropertyMetadata(false, IsEnabledChanged));
static Dictionary<object, MouseCapture> _captures = new Dictionary<object, MouseCapture>();
static void IsEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var target = d as FrameworkElement;
if (target == null) return;
if ((bool)e.NewValue)
{
target.Loaded += target_Loaded;
}
else
{
target_Unloaded(target, new RoutedEventArgs());
}
}
static void target_Unloaded(object sender, RoutedEventArgs e)
{
System.Diagnostics.Debug.WriteLine("Target Unloaded");
var target = sender as FrameworkElement;
if (null == target)
return;
_captures.Remove(sender);
target.Loaded -= target_Loaded;
target.Unloaded -= target_Unloaded;
target.PreviewMouseLeftButtonDown -= target_PreviewMouseLeftButtonDown;
target.PreviewMouseMove -= target_PreviewMouseMove;
target.PreviewMouseLeftButtonUp -= target_PreviewMouseLeftButtonUp;
}
static void target_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
var target = sender as FrameworkElement;
if (null == target)
return;
var scroller = FindVisualParent<ScrollViewer> (target);
if (null == scroller)
{
Trace.WriteLine ("Control should be placed inside ScrollViewer for drag scrolling to work");
return;
}
_captures[sender] = new MouseCapture
{
HorizontalOffset = scroller.HorizontalOffset,
VerticalOffset = scroller.VerticalOffset,
Point = e.GetPosition(scroller),
};
}
static void target_Loaded(object sender, RoutedEventArgs e)
{
var target = sender as FrameworkElement;
if (target == null) return;
// Debug.WriteLine("DragScroll target Loaded", sender);
target.Unloaded += target_Unloaded;
target.PreviewMouseLeftButtonDown += target_PreviewMouseLeftButtonDown;
target.PreviewMouseMove += target_PreviewMouseMove;
target.PreviewMouseLeftButtonUp += target_PreviewMouseLeftButtonUp;
}
static void target_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
var target = sender as FrameworkElement;
if (target == null) return;
target.ReleaseMouseCapture();
target.Cursor = Cursors.Arrow;
}
static void target_PreviewMouseMove(object sender, MouseEventArgs e)
{
if (!_captures.ContainsKey(sender)) return;
if (e.LeftButton != MouseButtonState.Pressed)
{
_captures.Remove(sender);
return;
}
var target = sender as FrameworkElement;
if (null == target)
return;
var scroller = FindVisualParent<ScrollViewer> (target);
if (null == scroller)
return;
var capture = _captures[sender];
var point = e.GetPosition (scroller);
var dx = point.X - capture.Point.X;
var dy = point.Y - capture.Point.Y;
if (System.Math.Abs(dy) > 5 || System.Math.Abs(dx) > 5)
{
target.CaptureMouse();
target.Cursor = Cursors.SizeAll;
}
scroller.ScrollToHorizontalOffset(capture.HorizontalOffset - dx);
scroller.ScrollToVerticalOffset(capture.VerticalOffset - dy);
}
static parentItem FindVisualParent<parentItem> (DependencyObject obj) where parentItem : DependencyObject
{
if (null == obj)
return null;
DependencyObject parent = VisualTreeHelper.GetParent (obj);
while (parent != null && !(parent is parentItem))
{
parent = VisualTreeHelper.GetParent (parent);
}
return parent as parentItem;
}
internal class MouseCapture
{
public double HorizontalOffset { get; set; }
public double VerticalOffset { get; set; }
public Point Point { get; set; }
}
}
}

37
ExtractArchive.xaml Normal file
View File

@ -0,0 +1,37 @@
<local:ExtractDialog x:Class="GARbro.GUI.ExtractArchiveDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="clr-namespace:GARbro.GUI.Strings"
xmlns:p="clr-namespace:GARbro.GUI.Properties"
xmlns:local="clr-namespace:GARbro.GUI"
Title="{x:Static s:guiStrings.TextExtractTitle}" Height="200" Width="411.713"
ShowInTaskbar="False" WindowStartupLocation="CenterOwner" ResizeMode="NoResize" Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}">
<Grid Margin="0,0,0,0">
<Grid.RowDefinitions>
<RowDefinition Height="61*"/>
<RowDefinition Height="70*"/>
<RowDefinition Height="41*"/>
</Grid.RowDefinitions>
<TextBlock x:Name="ExtractLabel" Text="{x:Static s:guiStrings.TextExtractAllTo}" Margin="10,10,10,0" VerticalAlignment="Top" Height="15"/>
<local:ExtAutoCompleteBox x:Name="DestinationDir" Margin="10,0,41,9" VerticalAlignment="Bottom"/>
<Button Margin="0,0,10,9" VerticalAlignment="Bottom" HorizontalAlignment="Right"
Command="{x:Static local:Commands.Browse}">
<Image Source="{StaticResource IconSearch}" Stretch="Uniform" UseLayoutRounding="True" SnapsToDevicePixels="True" Width="16" Height="16" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Button>
<CheckBox Name="ExtractImages" Content="{x:Static s:guiStrings.TextExtractImages}" HorizontalAlignment="Left" Margin="10,7.061,0,0" Grid.Row="1" VerticalAlignment="Top" Width="147" Height="15" IsChecked="True"/>
<Border BorderBrush="{x:Null}" Height="28" Width="115" Margin="0,0.061,127.87,0" Grid.Row="1" VerticalAlignment="Top" HorizontalAlignment="Right" >
<TextBlock Text="{x:Static s:guiStrings.TextSaveImagesAs}" TextWrapping="Wrap" TextAlignment="Right" VerticalAlignment="Center" HorizontalAlignment="Right"/>
</Border>
<ComboBox Name="ImageConversionFormat" DisplayMemberPath="Tag" Margin="0,4.061,41.87,0" Grid.Row="1" VerticalAlignment="Top" Height="21" HorizontalAlignment="Right" Width="75">
</ComboBox>
<CheckBox x:Name="ExtractText" Content="{x:Static s:guiStrings.TextExtractText}" HorizontalAlignment="Left" Margin="10,35.061,0,0" Grid.Row="1" VerticalAlignment="Top" Width="120" Height="15" IsChecked="True"/>
<TextBlock Text="{x:Static s:guiStrings.TextEncoding}" Margin="0,35.061,128,0" TextAlignment="Right" VerticalAlignment="Top" Height="20" Grid.Row="1" HorizontalAlignment="Right" Width="109"/>
<ComboBox x:Name="TextEncoding" Margin="0,33.061,41.87,0" Grid.Row="1" VerticalAlignment="Top" Height="21" HorizontalAlignment="Right" Width="76">
</ComboBox>
<Button Content="{x:Static s:guiStrings.ButtonExtract}" Click="ExtractButton_Click" HorizontalAlignment="Right" Margin="0,0,103,10" Grid.Row="2" Width="75" Height="21" VerticalAlignment="Bottom" IsDefault="True"/>
<Button Content="{x:Static s:guiStrings.ButtonCancel}" Margin="0,0,10,10" Grid.Row="2" Height="21" VerticalAlignment="Bottom" IsCancel="True" HorizontalAlignment="Right" Width="75"/>
</Grid>
<Window.CommandBindings>
<CommandBinding Command="{x:Static local:Commands.Browse}" Executed="BrowseExec" CanExecute="CanExecuteAlways"/>
</Window.CommandBindings>
</local:ExtractDialog>

80
ExtractArchive.xaml.cs Normal file
View File

@ -0,0 +1,80 @@
// Game Resource Browser
//
// Copyright (C) 2014 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.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Diagnostics;
using Microsoft.WindowsAPICodePack.Dialogs;
using GARbro.GUI.Properties;
using GARbro.GUI.Strings;
using GameRes;
namespace GARbro.GUI
{
/// <summary>
/// Interaction logic for ExtractArchive.xaml
/// </summary>
public partial class ExtractArchiveDialog : ExtractDialog
{
public ExtractArchiveDialog (string filename, string destination)
{
InitializeComponent();
ExtractLabel.Text = string.Format (guiStrings.TextExtractAllTo, filename);
DestinationDir.Text = destination;
ExtractImages.IsChecked = Settings.Default.appExtractImages;
ExtractText.IsChecked = Settings.Default.appExtractText;
ExtractText.IsEnabled = false;
TextEncoding.IsEnabled = false;
InitImageFormats (ImageConversionFormat);
}
private void BrowseExec (object sender, ExecutedRoutedEventArgs e)
{
string folder = ChooseFolder (guiStrings.TextChooseDestDir, DestinationDir.Text);
if (null != folder)
DestinationDir.Text = folder;
}
void ExtractButton_Click (object sender, RoutedEventArgs e)
{
this.DialogResult = true;
Settings.Default.appExtractImages = this.ExtractImages.IsChecked.Value;
Settings.Default.appExtractText = this.ExtractText.IsChecked.Value;
ExportImageFormat (ImageConversionFormat);
}
public ImageFormat GetImageFormat ()
{
var selected = ImageConversionFormat.SelectedItem as ImageFormatModel;
return null != selected ? selected.Source : null;
}
}
}

83
ExtractDialog.cs Normal file
View File

@ -0,0 +1,83 @@
//! \file ExtractDialog.cs
//! \date Wed Jul 09 11:26:08 2014
//! \brief Extract dialog window.
//
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using Microsoft.WindowsAPICodePack.Dialogs;
using GARbro.GUI.Properties;
using GARbro.GUI.Strings;
using GameRes;
using System.Windows.Input;
using System.IO;
using System.Diagnostics;
using System.Collections.Generic;
namespace GARbro.GUI
{
public partial class ExtractDialog : Window
{
public void InitImageFormats (ComboBox image_format)
{
var default_format = Settings.Default.appImageFormat;
var formats = FormatCatalog.Instance.ImageFormats.Where (f => f.IsBuiltin);
ImageFormatModel[] default_model = { new ImageFormatModel() };
var models = default_model.Concat (formats.Select (f => new ImageFormatModel (f))).ToList();
var selected = models.FirstOrDefault (f => f.Tag.Equals (default_format));
image_format.ItemsSource = models;
Trace.WriteLine (selected != null ? selected.Tag : "null", "image_format");
if (null != selected)
image_format.SelectedItem = selected;
else if (models.Any())
image_format.SelectedIndex = 0;
}
public ImageFormat GetImageFormat (ComboBox image_format)
{
var selected = image_format.SelectedItem as ImageFormatModel;
if (null != selected)
return selected.Source;
else
return null;
}
public void ExportImageFormat (ComboBox image_format)
{
var format = GetImageFormat (image_format);
if (null != format)
Settings.Default.appImageFormat = format.Tag;
else
Settings.Default.appImageFormat = "";
}
public string ChooseFolder (string title, string initial)
{
var dlg = new CommonOpenFileDialog();
dlg.Title = title;
dlg.IsFolderPicker = true;
dlg.InitialDirectory = initial;
dlg.AddToMostRecentlyUsedList = false;
dlg.AllowNonFileSystemItems = false;
dlg.EnsureFileExists = true;
dlg.EnsurePathExists = true;
dlg.EnsureReadOnly = false;
dlg.EnsureValidNames = true;
dlg.Multiselect = false;
dlg.ShowPlacesList = true;
if (dlg.ShowDialog (this) == CommonFileDialogResult.Ok)
return dlg.FileName;
else
return null;
}
public void CanExecuteAlways (object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
}
}
}

34
ExtractFile.xaml Normal file
View File

@ -0,0 +1,34 @@
<local:ExtractDialog x:Class="GARbro.GUI.ExtractFile"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="clr-namespace:GARbro.GUI.Strings"
xmlns:p="clr-namespace:GARbro.GUI.Properties"
xmlns:local="clr-namespace:GARbro.GUI"
Title="{x:Static s:guiStrings.TextExtractTitle}" Height="165.774" Width="400.861"
ShowInTaskbar="False" WindowStartupLocation="CenterOwner" ResizeMode="NoResize" Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}">
<Grid VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock x:Name="ExtractLabel" Text="{x:Static s:guiStrings.TextExtractFileTo}" Margin="10,10,9.157,0" VerticalAlignment="Top" Height="15"/>
<local:ExtAutoCompleteBox x:Name="DestinationDir" Margin="10,28,0,0"
VerticalAlignment="Top" HorizontalAlignment="Left" Width="337"/>
<Button Margin="0,28,10,0" VerticalAlignment="Top" HorizontalAlignment="Right"
Command="{x:Static local:Commands.Browse}">
<Image Source="{StaticResource IconSearch}" Stretch="Uniform" UseLayoutRounding="True" SnapsToDevicePixels="True" Width="16" Height="16" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Button>
<StackPanel x:Name="ImageConversionOptions" Visibility="Visible" Orientation="Horizontal" Margin="10,60,0,0" Height="25" VerticalAlignment="Top" HorizontalAlignment="Left" Width="300">
<TextBlock Text="{x:Static s:guiStrings.TextSaveAs}" Margin="0,0,7,0" TextWrapping="Wrap" TextAlignment="Right" VerticalAlignment="Center" HorizontalAlignment="Left"/>
<ComboBox x:Name="ImageConversionFormat" DisplayMemberPath="Tag" Margin="0" VerticalAlignment="Center" Height="21" Width="76"/>
</StackPanel>
<StackPanel x:Name="TextConversionOptions" Visibility="Collapsed" Orientation="Horizontal" Margin="10,60,0,0" Height="25" VerticalAlignment="Top" HorizontalAlignment="Left" Width="300">
<TextBlock Text="{x:Static s:guiStrings.TextEncoding}" Margin="0,0,7,0" TextAlignment="Right" VerticalAlignment="Center" HorizontalAlignment="Right"/>
<ComboBox x:Name="TextEncoding" Margin="0" VerticalAlignment="Center" Height="21" HorizontalAlignment="Right" Width="76"/>
</StackPanel>
<Button Content="{x:Static s:guiStrings.ButtonExtract}" Click="ExtractButton_Click" HorizontalAlignment="Right" Margin="0,0,102.157,10" Width="75" IsDefault="True" Height="21" VerticalAlignment="Bottom"/>
<Button Content="{x:Static s:guiStrings.ButtonCancel}" Margin="0,0,10.157,10" IsCancel="True" HorizontalAlignment="Right" Width="75" Height="21" VerticalAlignment="Bottom"/>
</Grid>
<Window.CommandBindings>
<CommandBinding Command="{x:Static local:Commands.Browse}" Executed="BrowseExec" CanExecute="CanExecuteAlways"/>
</Window.CommandBindings>
</local:ExtractDialog>

83
ExtractFile.xaml.cs Normal file
View File

@ -0,0 +1,83 @@
// Game Resource Browser
//
// Copyright (C) 2014 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.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using Microsoft.WindowsAPICodePack.Dialogs;
using GARbro.GUI.Properties;
using GARbro.GUI.Strings;
namespace GARbro.GUI
{
/// <summary>
/// Interaction logic for ExtractFile.xaml
/// </summary>
public partial class ExtractFile : ExtractDialog
{
public ExtractFile (EntryViewModel entry, string destination)
{
InitializeComponent();
ExtractLabel.Text = string.Format (guiStrings.TextExtractFileTo, entry.Name);
DestinationDir.Text = destination;
if ("image" == entry.Type)
{
ImageConversionOptions.Visibility = Visibility.Visible;
TextConversionOptions.Visibility = Visibility.Collapsed;
InitImageFormats (ImageConversionFormat);
}
else if ("script" == entry.Type)
{
ImageConversionOptions.Visibility = Visibility.Collapsed;
TextConversionOptions.Visibility = Visibility.Visible;
TextEncoding.IsEnabled = false;
}
else
{
ImageConversionOptions.Visibility = Visibility.Collapsed;
TextConversionOptions.Visibility = Visibility.Collapsed;
}
}
private void BrowseExec (object sender, ExecutedRoutedEventArgs e)
{
string folder = ChooseFolder (guiStrings.TextChooseDestDir, DestinationDir.Text);
if (null != folder)
DestinationDir.Text = folder;
}
void ExtractButton_Click (object sender, RoutedEventArgs e)
{
this.DialogResult = true;
if (ImageConversionOptions.Visibility == Visibility.Visible)
{
ExportImageFormat (ImageConversionFormat);
}
}
}
}

305
GARbro.GUI.csproj Normal file
View File

@ -0,0 +1,305 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{2935BE57-C4E0-43E7-86DE-C1848C820B19}</ProjectGuid>
<OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>GARbro.GUI</RootNamespace>
<AssemblyName>GARbro.GUI</AssemblyName>
<TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<WarningLevel>4</WarningLevel>
<IsWebBootstrapper>false</IsWebBootstrapper>
<TargetFrameworkProfile />
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
<UpdateEnabled>false</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
<UpdateInterval>7</UpdateInterval>
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
<UpdatePeriodically>false</UpdatePeriodically>
<UpdateRequired>false</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<UseApplicationTrust>false</UseApplicationTrust>
<PublishWizardCompleted>true</PublishWizardCompleted>
<BootstrapperEnabled>true</BootstrapperEnabled>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>
</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>Images\sample.ico</ApplicationIcon>
</PropertyGroup>
<PropertyGroup>
<ManifestCertificateThumbprint>751F4A9FD4F4CC3D99D70509FF1F9D9CC9E49516</ManifestCertificateThumbprint>
</PropertyGroup>
<PropertyGroup>
<ManifestKeyFile>GARbro.GUI_TemporaryKey.pfx</ManifestKeyFile>
</PropertyGroup>
<PropertyGroup>
<GenerateManifests>false</GenerateManifests>
</PropertyGroup>
<PropertyGroup>
<TargetZone>LocalIntranet</TargetZone>
</PropertyGroup>
<PropertyGroup>
<ApplicationManifest>Properties\app.manifest</ApplicationManifest>
</PropertyGroup>
<PropertyGroup>
<SignManifests>true</SignManifests>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.VisualBasic" />
<Reference Include="Microsoft.WindowsAPICodePack">
<HintPath>packages\WindowsAPICodePack-Core.1.1\lib\Microsoft.WindowsAPICodePack.dll</HintPath>
</Reference>
<Reference Include="Microsoft.WindowsAPICodePack.Shell">
<HintPath>packages\WindowsAPICodePack-Shell.1.1\lib\Microsoft.WindowsAPICodePack.Shell.dll</HintPath>
</Reference>
<Reference Include="Ookii.Dialogs.Wpf, Version=1.0.0.0, Culture=neutral, PublicKeyToken=0c15020868fd6249, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>packages\Ookii.Dialogs.1.0\lib\net35\Ookii.Dialogs.Wpf.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Windows.Controls.Input.Toolkit, Version=3.5.40128.1, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>D:\Program Files\WPF Toolkit\v3.5.50211.1\System.Windows.Controls.Input.Toolkit.dll</HintPath>
</Reference>
<Reference Include="System.Xml" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Xaml">
<RequiredTargetFramework>4.0</RequiredTargetFramework>
</Reference>
<Reference Include="WindowsBase" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
<Reference Include="WPFToolkit, Version=3.5.40128.1, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>D:\Program Files\WPF Toolkit\v3.5.50211.1\WPFToolkit.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="App.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</ApplicationDefinition>
<Compile Include="AboutBox.xaml.cs">
<DependentUpon>AboutBox.xaml</DependentUpon>
</Compile>
<Compile Include="ArcParameters.xaml.cs">
<DependentUpon>ArcParameters.xaml</DependentUpon>
</Compile>
<Compile Include="DragScroll.cs" />
<Compile Include="ExtractArchive.xaml.cs">
<DependentUpon>ExtractArchive.xaml</DependentUpon>
</Compile>
<Compile Include="ExtractDialog.cs" />
<Compile Include="ExtractFile.xaml.cs">
<DependentUpon>ExtractFile.xaml</DependentUpon>
</Compile>
<Compile Include="HistoryStack.cs" />
<Compile Include="ImagePreview.cs" />
<Compile Include="ModalWindow.cs" />
<Compile Include="Settings.cs" />
<Compile Include="Strings\guiStrings.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>guiStrings.resx</DependentUpon>
</Compile>
<Compile Include="Utility.cs" />
<Compile Include="ViewModel.cs" />
<Page Include="AboutBox.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="ArcParameters.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="ExtractArchive.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="ExtractFile.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="MainWindow.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Compile Include="App.xaml.cs">
<DependentUpon>App.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="MainWindow.xaml.cs">
<DependentUpon>MainWindow.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
<EmbeddedResource Include="Strings\guiStrings.resx">
<Generator>PublicResXFileCodeGenerator</Generator>
<LastGenOutput>guiStrings.Designer.cs</LastGenOutput>
</EmbeddedResource>
<EmbeddedResource Include="Strings\guiStrings.ru-RU.resx" />
<None Include="packages.config" />
<None Include="Properties\app.manifest" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<AppDesigner Include="Properties\" />
</ItemGroup>
<ItemGroup>
<None Include="App.config">
<SubType>Designer</SubType>
</None>
</ItemGroup>
<ItemGroup>
<Resource Include="Images\16x16\add file.png" />
<Resource Include="Images\16x16\add folder.png" />
<Resource Include="Images\16x16\add note.png" />
<Resource Include="Images\16x16\add window.png" />
<Resource Include="Images\16x16\add.png" />
<Resource Include="Images\16x16\addd.png" />
<Resource Include="Images\16x16\flag green.png" />
<Resource Include="Images\16x16\folder video.png" />
<Resource Include="Images\16x16\folder.png" />
<Resource Include="Images\16x16\info.png" />
<Resource Include="Images\16x16\play.png" />
<Resource Include="Images\16x16\remove.png" />
<Resource Include="Images\16x16\tools.png" />
<Resource Include="Images\16x16\undo.png" />
<Resource Include="Images\16x16\video.png" />
<Resource Include="Images\32x32\add file.png" />
<Resource Include="Images\32x32\add folder.png" />
<Resource Include="Images\32x32\add note.png" />
<Resource Include="Images\32x32\add window.png" />
<Resource Include="Images\32x32\add.png" />
<Resource Include="Images\32x32\addd.png" />
<Resource Include="Images\32x32\back button.png" />
<Resource Include="Images\32x32\back.png" />
<Resource Include="Images\32x32\delete.png" />
<Resource Include="Images\32x32\flag green.png" />
<Resource Include="Images\32x32\folder video.png" />
<Resource Include="Images\32x32\folder.png" />
<Resource Include="Images\32x32\forward button.png" />
<Resource Include="Images\32x32\help.png" />
<Resource Include="Images\32x32\info.png" />
<Resource Include="Images\32x32\play.png" />
<Resource Include="Images\32x32\remove.png" />
<Resource Include="Images\32x32\tools.png" />
<Resource Include="Images\32x32\undo.png" />
<Resource Include="Images\32x32\video.png" />
<Resource Include="Images\64x64\add file.png" />
<Resource Include="Images\64x64\add folder.png" />
<Resource Include="Images\64x64\add note.png" />
<Resource Include="Images\64x64\add window.png" />
<Resource Include="Images\64x64\add.png" />
<Resource Include="Images\64x64\addd.png" />
<Resource Include="Images\64x64\folder video.png" />
<Resource Include="Images\64x64\folder.png" />
<Resource Include="Images\64x64\info.png" />
<Resource Include="Images\64x64\play.png" />
<Resource Include="Images\64x64\remove.png" />
<Resource Include="Images\64x64\tools.png" />
<Resource Include="Images\64x64\undo.png" />
<Resource Include="Images\64x64\video.png" />
<Resource Include="Images\sample.ico" />
</ItemGroup>
<ItemGroup>
<Content Include="zlib\zlib32.dll">
<Link>zlib32.dll</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="zlib\zlib64.dll">
<Link>zlib64.dll</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Resource Include="Images\search4files.ico" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="ArcFormats\ArcFormats.csproj">
<Project>{a8865685-27cc-427b-ac38-e48d2ad05df4}</Project>
<Name>ArcFormats</Name>
</ProjectReference>
<ProjectReference Include="GameRes\GameRes.csproj">
<Project>{453c087f-e416-4ae9-8c03-d8760da0574b}</Project>
<Name>GameRes</Name>
<EmbedInteropTypes>False</EmbedInteropTypes>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include=".NETFramework,Version=v4.5">
<Visible>False</Visible>
<ProductName>Microsoft .NET Framework 4.5 %28x86 and x64%29</ProductName>
<Install>true</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
<Install>false</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1</ProductName>
<Install>false</Install>
</BootstrapperPackage>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

17
GARbro.GUI.csproj.user Normal file
View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<PublishUrlHistory>publish\</PublishUrlHistory>
<InstallUrlHistory />
<SupportUrlHistory />
<UpdateUrlHistory />
<BootstrapperUrlHistory />
<ErrorReportUrlHistory />
<FallbackCulture>en-US</FallbackCulture>
<VerifyUploadedFiles>false</VerifyUploadedFiles>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'">
<StartArguments>
</StartArguments>
</PropertyGroup>
</Project>

59
GARbro.sln Normal file
View File

@ -0,0 +1,59 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013
VisualStudioVersion = 12.0.21005.1
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
{453C087F-E416-4AE9-8C03-D8760DA0574B} = {453C087F-E416-4AE9-8C03-D8760DA0574B}
{A8865685-27CC-427B-AC38-E48D2AD05DF4} = {A8865685-27CC-427B-AC38-E48D2AD05DF4}
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ArcFormats", "ArcFormats\ArcFormats.csproj", "{A8865685-27CC-427B-AC38-E48D2AD05DF4}"
ProjectSection(ProjectDependencies) = postProject
{453C087F-E416-4AE9-8C03-D8760DA0574B} = {453C087F-E416-4AE9-8C03-D8760DA0574B}
EndProjectSection
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
{A8865685-27CC-427B-AC38-E48D2AD05DF4} = {A8865685-27CC-427B-AC38-E48D2AD05DF4}
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
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}.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}.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}.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}.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}.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
EndGlobalSection
EndGlobal

245
GameRes/ArcFile.cs Normal file
View File

@ -0,0 +1,245 @@
//! \file ArcFile.cs
//! \date Tue Jul 08 12:53:45 2014
//! \brief Game Archive file class.
//
using System;
using System.IO;
using System.Linq;
using System.Collections.Generic;
using System.Diagnostics;
namespace GameRes
{
public enum ExtractAction
{
Abort,
Skip,
Continue,
}
public class ArcFile : IDisposable
{
private ArcView m_arc;
private ArchiveFormat m_interface;
private ICollection<Entry> m_dir;
/// <summary>Tag that identifies this archive format.</summary>
public string Tag { get { return m_interface.Tag; } }
/// <summary>Short archive format description.</summary>
public string Description { get { return m_interface.Description; } }
/// <summary>Memory-mapped view of the archive.</summary>
public ArcView File { get { return m_arc; } }
/// <summary>Archive contents.</summary>
public ICollection<Entry> Dir { get { return m_dir; } }
public delegate ExtractAction ExtractCallback (int num, Entry entry);
public ArcFile (ArcView arc, ArchiveFormat impl, ICollection<Entry> dir)
{
m_arc = arc;
m_interface = impl;
m_dir = dir;
}
/// <summary>
/// Try to open <paramref name="filename"/> as archive.
/// Returns: ArcFile object if file is opened successfully, null otherwise.
/// </summary>
public static ArcFile TryOpen (string filename)
{
var file = new ArcView (filename);
try
{
uint signature = file.View.ReadUInt32 (0);
for (;;)
{
var range = FormatCatalog.Instance.LookupSignature<ArchiveFormat> (signature);
foreach (var impl in range)
{
try
{
var arc = impl.TryOpen (file);
if (null != arc)
{
file = null; // file ownership passed to ArcFile
return arc;
}
}
catch (Exception X)
{
// ignore failed open attmepts
Trace.WriteLine (string.Format ("[{0}] {1}: {2}", impl.Tag, filename, X.Message));
FormatCatalog.Instance.LastError = X;
}
}
if (0 == signature)
break;
signature = 0;
}
}
finally
{
if (null != file)
file.Dispose();
}
return null;
}
/// <summary>
/// Extract all entries from the archive into current directory.
/// <paramref name="callback"/> could be used to observe/control extraction process.
/// </summary>
public void ExtractFiles (ExtractCallback callback)
{
int i = 0;
foreach (var entry in Dir.OrderBy (e => e.Offset))
{
var action = callback (i, entry);
if (ExtractAction.Abort == action)
break;
if (ExtractAction.Skip != action)
Extract (entry);
++i;
}
}
/// <summary>
/// Extract specified <paramref name="entry"/> into current directory.
/// </summary>
public void Extract (Entry entry)
{
if (-1 != entry.Offset)
m_interface.Extract (this, entry);
}
/// <summary>
/// Open specified <paramref name="entry"/> as Stream.
/// </summary>
public Stream OpenEntry (Entry entry)
{
return m_interface.OpenEntry (this, entry);
}
/// <summary>
/// Create file corresponding to <paramref name="entry"/> within current directory and open
/// it for writing.
/// </summary>
public Stream CreateFile (Entry entry)
{
return m_interface.CreateFile (entry);
}
#region IDisposable Members
bool disposed = false;
public void Dispose ()
{
Dispose (true);
GC.SuppressFinalize (this);
}
protected virtual void Dispose (bool disposing)
{
if (!disposed)
{
if (disposing)
m_arc.Dispose();
m_arc = null;
disposed = true;
}
}
#endregion
}
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);
}
}
}
}

470
GameRes/ArcView.cs Normal file
View File

@ -0,0 +1,470 @@
//! \file ArcView.cs
//! \date Mon Jul 07 10:31:10 2014
//! \brief Memory mapped view of gameres file.
//
using System;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Runtime.InteropServices;
using System.Text;
namespace GameRes
{
public static class Encodings
{
public static readonly Encoding cp932 = Encoding.GetEncoding (932);
}
public static class StreamExtension
{
static public string ReadStringUntil (this Stream file, byte delim, Encoding enc)
{
byte[] buffer = new byte[16];
int size = 0;
for (;;)
{
int b = file.ReadByte ();
if (-1 == b || delim == b)
break;
if (buffer.Length == size)
{
byte[] new_buffer = new byte[checked(size/2*3)];
Array.Copy (buffer, new_buffer, size);
buffer = new_buffer;
}
buffer[size++] = (byte)b;
}
return enc.GetString (buffer, 0, size);
}
static public string ReadCString (this Stream file, Encoding enc)
{
return ReadStringUntil (file, 0, enc);
}
static public string ReadCString (this Stream file)
{
return ReadStringUntil (file, 0, Encodings.cp932);
}
}
public static class MappedViewExtension
{
static public string ReadString (this MemoryMappedViewAccessor view, long offset, uint size, Encoding enc)
{
byte[] buffer = new byte[size];
uint n;
for (n = 0; n < size; ++n)
{
byte b = view.ReadByte (offset+n);
if (0 == b)
break;
buffer[n] = b;
}
return enc.GetString (buffer, 0, (int)n);
}
static public string ReadString (this MemoryMappedViewAccessor view, long offset, uint size)
{
return ReadString (view, offset, size, Encodings.cp932);
}
unsafe public static byte* GetPointer (this MemoryMappedViewAccessor view, long offset)
{
var num = view.PointerOffset % info.dwAllocationGranularity;
byte* ptr = null;
view.SafeMemoryMappedViewHandle.AcquirePointer (ref ptr);
ptr += num;
return ptr;
}
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern void GetSystemInfo (ref SYSTEM_INFO lpSystemInfo);
internal struct SYSTEM_INFO
{
internal int dwOemId;
internal int dwPageSize;
internal IntPtr lpMinimumApplicationAddress;
internal IntPtr lpMaximumApplicationAddress;
internal IntPtr dwActiveProcessorMask;
internal int dwNumberOfProcessors;
internal int dwProcessorType;
internal int dwAllocationGranularity;
internal short wProcessorLevel;
internal short wProcessorRevision;
}
static SYSTEM_INFO info;
static MappedViewExtension()
{
GetSystemInfo (ref info);
}
}
public class ArcView : IDisposable
{
private MemoryMappedFile m_map;
public const long PageSize = 4096;
public long MaxOffset { get; private set; }
public Frame View { get; private set; }
public ArcView (string name)
{
using (var fs = new FileStream(name, FileMode.Open, FileAccess.Read, FileShare.Read))
{
MaxOffset = fs.Length;
m_map = MemoryMappedFile.CreateFromFile (fs, null, 0,
MemoryMappedFileAccess.Read, null, HandleInheritability.None, false);
try {
View = new Frame (this);
} catch {
m_map.Dispose(); // dispose on error only
throw;
}
}
}
public Frame CreateFrame ()
{
return new Frame (View);
}
public ArcStream CreateStream ()
{
return new ArcStream (this);
}
public ArcStream CreateStream (long offset, uint size)
{
return new ArcStream (this, offset, size);
}
public MemoryMappedViewAccessor CreateViewAccessor (long offset, uint size)
{
return m_map.CreateViewAccessor (offset, size, MemoryMappedFileAccess.Read);
}
#region IDisposable Members
bool disposed = false;
public void Dispose ()
{
Dispose (true);
GC.SuppressFinalize (this);
}
protected virtual void Dispose (bool disposing)
{
if (!disposed)
{
if (disposing)
{
View.Dispose();
m_map.Dispose();
}
disposed = true;
m_map = null;
}
}
#endregion
public class Frame : IDisposable
{
private ArcView m_arc;
private MemoryMappedViewAccessor m_view;
private long m_offset;
private uint m_size;
public long Offset { get { return m_offset; } }
public uint Reserved { get { return m_size; } }
public Frame (ArcView arc)
{
m_arc = arc;
m_offset = 0;
m_size = (uint)Math.Min (ArcView.PageSize, m_arc.MaxOffset);
m_view = m_arc.CreateViewAccessor (m_offset, m_size);
}
public Frame (Frame other)
{
m_arc = other.m_arc;
m_offset = 0;
m_size = (uint)Math.Min (ArcView.PageSize, m_arc.MaxOffset);
m_view = m_arc.CreateViewAccessor (m_offset, m_size);
}
public Frame (ArcView arc, long offset, uint size)
{
m_arc = arc;
m_offset = Math.Min (offset, m_arc.MaxOffset);
m_size = (uint)Math.Min (size, m_arc.MaxOffset-m_offset);
m_view = m_arc.CreateViewAccessor (m_offset, m_size);
}
public uint Reserve (long offset, uint size)
{
if (offset < m_offset || offset+size > m_offset+m_size)
{
if (offset > m_arc.MaxOffset)
throw new ArgumentOutOfRangeException ("offset", "Too large offset specified for memory mapped file view.");
if (size < ArcView.PageSize)
size = (uint)ArcView.PageSize;
if (size > m_arc.MaxOffset-offset)
size = (uint)(m_arc.MaxOffset-offset);
m_view.Dispose();
m_view = m_arc.CreateViewAccessor (offset, size);
m_offset = offset;
m_size = size;
}
return (uint)(m_offset + m_size - offset);
}
public bool AsciiEqual (long offset, string data)
{
if (Reserve (offset, (uint)data.Length) < (uint)data.Length)
return false;
unsafe
{
byte* ptr = m_view.GetPointer (m_offset);
try {
for (int i = 0; i < data.Length; ++i)
{
if (ptr[offset-m_offset+i] != data[i])
return false;
}
} finally {
m_view.SafeMemoryMappedViewHandle.ReleasePointer();
}
return true;
}
}
public int Read (long offset, byte[] buf, int buf_offset, uint count)
{
// supposedly faster version of
//Reserve (offset, count);
//return m_view.ReadArray (offset-m_offset, buf, buf_offset, (int)count);
if (buf == null)
throw new ArgumentNullException ("buf", "Buffer cannot be null.");
if (buf_offset < 0)
throw new ArgumentOutOfRangeException ("buf_offset", "Buffer offset should be non-negative.");
int total = (int)Math.Min (Reserve (offset, count), count);
if (buf.Length - buf_offset < total)
throw new ArgumentException ("Buffer offset and length are out of bounds.");
unsafe
{
byte* ptr = m_view.GetPointer (m_offset);
try {
Marshal.Copy ((IntPtr)(ptr+(offset-m_offset)), buf, buf_offset, total);
} finally {
m_view.SafeMemoryMappedViewHandle.ReleasePointer();
}
}
return total;
}
public byte ReadByte (long offset)
{
Reserve (offset, 1);
return m_view.ReadByte (offset-m_offset);
}
public ushort ReadUInt16 (long offset)
{
Reserve (offset, 2);
return m_view.ReadUInt16 (offset-m_offset);
}
public short ReadInt16 (long offset)
{
Reserve (offset, 2);
return m_view.ReadInt16 (offset-m_offset);
}
public uint ReadUInt32 (long offset)
{
Reserve (offset, 4);
return m_view.ReadUInt32 (offset-m_offset);
}
public int ReadInt32 (long offset)
{
Reserve (offset, 4);
return m_view.ReadInt32 (offset-m_offset);
}
public ulong ReadUInt64 (long offset)
{
Reserve (offset, 8);
return m_view.ReadUInt64 (offset-m_offset);
}
public long ReadInt64 (long offset)
{
Reserve (offset, 8);
return m_view.ReadInt64 (offset-m_offset);
}
public string ReadString (long offset, uint size, Encoding enc)
{
Reserve (offset, size);
return m_view.ReadString (offset-m_offset, size, enc);
}
public string ReadString (long offset, uint size)
{
return ReadString (offset, size, Encodings.cp932);
}
#region IDisposable Members
bool disposed = false;
public void Dispose ()
{
Dispose (true);
GC.SuppressFinalize (this);
}
protected virtual void Dispose (bool disposing)
{
if (!disposed)
{
if (disposing)
{
m_view.Dispose();
}
m_arc = null;
m_view = null;
disposed = true;
}
}
#endregion
}
public class ArcStream : System.IO.Stream
{
private Frame m_view;
private long m_start;
private uint m_size;
private long m_position;
public override bool CanRead { get { return true; } }
public override bool CanSeek { get { return true; } }
public override bool CanWrite { get { return false; } }
public override long Length { get { return m_size; } }
public override long Position
{
get { return m_position; }
set { m_position = Math.Max (value, 0); }
}
public ArcStream (ArcView file)
{
m_view = file.CreateFrame();
m_start = 0;
m_size = (uint)Math.Min (file.MaxOffset, uint.MaxValue);
m_position = 0;
}
public ArcStream (ArcView file, long offset, uint size)
{
m_view = new Frame (file, offset, size);
m_start = m_view.Offset;
m_size = m_view.Reserved;
m_position = 0;
}
/// <summary>
/// Read stream signature (first 4 bytes) without altering current read position.
/// </summary>
public uint ReadSignature ()
{
return m_view.ReadUInt32 (m_start);
}
#region System.IO.Stream methods
public override void Flush()
{
}
public override long Seek (long offset, SeekOrigin origin)
{
switch (origin)
{
case SeekOrigin.Begin: m_position = offset; break;
case SeekOrigin.Current: m_position += offset; break;
case SeekOrigin.End: m_position = m_size + offset; break;
}
if (m_position < 0)
m_position = 0;
return m_position;
}
public override void SetLength (long length)
{
throw new NotSupportedException ("GameRes.ArcStream.SetLength method is not supported");
}
public override int Read (byte[] buffer, int offset, int count)
{
if (m_position >= m_size)
return 0;
count = (int)Math.Min (count, m_size - m_position);
int read = m_view.Read (m_start + m_position, buffer, offset, (uint)count);
m_position += read;
return read;
}
public override int ReadByte ()
{
if (m_position >= m_size)
return -1;
byte b = m_view.ReadByte (m_start+m_position);
++m_position;
return b;
}
public override void Write (byte[] buffer, int offset, int count)
{
throw new NotSupportedException("GameRes.ArcStream.Write method is not supported");
}
public override void WriteByte (byte value)
{
throw new NotSupportedException("GameRes.ArcStream.WriteByte method is not supported");
}
#endregion
#region IDisposable Members
bool disposed = false;
protected override void Dispose (bool disposing)
{
if (!disposed)
{
if (disposing)
{
m_view.Dispose();
}
disposed = true;
base.Dispose (disposing);
}
}
#endregion
}
public class Reader : System.IO.BinaryReader
{
public Reader (Stream stream) : base (stream, Encoding.ASCII, true)
{
}
}
}
}

347
GameRes/GameRes.cs Normal file
View File

@ -0,0 +1,347 @@
//! \file GameRes.cs
//! \date Mon Jun 30 20:12:13 2014
//! \brief game resources browser.
//
using System;
using System.IO;
using System.Text;
using System.Linq;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Reflection;
using GameRes.Collections;
using GameRes.Strings;
namespace GameRes
{
/// <summary>
/// Basic filesystem entry.
/// </summary>
public class Entry
{
public virtual string Name { get; set; }
public virtual string Type { get; set; }
public long Offset { get; set; }
public uint Size { get; set; }
public Entry ()
{
Type = "";
Offset = -1;
}
/// <summary>
/// Check whether entry lies within specified file bound.
/// </summary>
public bool CheckPlacement (long max_offset)
{
return Offset < max_offset && Size < max_offset && Offset <= max_offset - Size;
}
}
public class PackedEntry : Entry
{
public uint UnpackedSize { get; set; }
public bool IsPacked { get; set; }
}
public abstract class IResource
{
/// <summary>Short tag sticked to resource (usually filename extension)</summary>
public abstract string Tag { get; }
/// <summary>Resource description (its source/inventor)</summary>
public abstract string Description { get; }
/// <summary>Resource type (image/archive/script)</summary>
public abstract string Type { get; }
/// <summary>First 4 bytes of the resource file as little-endian 32-bit integer,
/// or zero if it could vary.</summary>
public abstract uint Signature { get; }
/// <summary>Signatures peculiar to the resource (the one above is also included here).</summary>
public IEnumerable<uint> Signatures
{
get { return m_signatures; }
protected set { m_signatures = value; }
}
/// <summary>Filename extensions peculiar to the resource.</summary>
public IEnumerable<string> Extensions
{
get { return m_extensions; }
protected set { m_extensions = value; }
}
/// <summary>
/// Create empty Entry that corresponds to implemented resource.
/// </summary>
public virtual Entry CreateEntry ()
{
return new Entry { Type = this.Type };
}
private IEnumerable<string> m_extensions;
private IEnumerable<uint> m_signatures;
protected IResource ()
{
m_extensions = new string[] { Tag.ToLower() };
m_signatures = new uint[] { Signature };
}
}
public class ResourceOptions
{
public object Widget { get; set; }
}
public abstract class ArchiveFormat : IResource
{
public override string Type { get { return "archive"; } }
public abstract ArcFile TryOpen (ArcView view);
/// <summary>
/// Extract file referenced by <paramref name="entry"/> into current directory.
/// </summary>
public virtual void Extract (ArcFile file, Entry entry)
{
using (var reader = OpenEntry (file, entry))
{
using (var writer = CreateFile (entry))
{
reader.CopyTo (writer);
}
}
}
/// <summary>
/// Open file referenced by <paramref name="entry"/> as Stream.
/// </summary>
public virtual Stream OpenEntry (ArcFile arc, Entry entry)
{
return arc.File.CreateStream (entry.Offset, entry.Size);
}
/// <summary>
/// Create file corresponding to <paramref name="entry"/> in current directory and open it
/// for writing.
/// </summary>
public virtual Stream CreateFile (Entry entry)
{
string dir = Path.GetDirectoryName (entry.Name);
if (!string.IsNullOrEmpty (dir))
{
Directory.CreateDirectory (dir);
}
return File.Create (entry.Name);
}
/// /// <summary>
/// Create resource archive named <paramref name="filename"/> containing entries from the
/// supplied <paramref name="list"/> and applying necessary <paramref name="options"/>.
/// </summary>
public virtual void Create (string filename, IEnumerable<Entry> list, ResourceOptions options = null)
{
throw new NotImplementedException ("ArchiveFormat.Create is not implemented");
}
public virtual ResourceOptions GetOptions ()
{
return null;
}
}
public delegate void ParametersRequestEventHandler (object sender, ParametersRequestEventArgs e);
public class ParametersRequestEventArgs : EventArgs
{
/// <summary>
/// String describing request nature (encryption key etc).
/// </summary>
public string Notice { get; set; }
/// <summary>
/// UIElement responsible for displaying request.
/// </summary>
public object InputWidget { get; set; }
/// <summary>
/// Return value from ShowDialog()
/// </summary>
public bool InputResult { get; set; }
}
public sealed class FormatCatalog
{
private static readonly FormatCatalog m_instance = new FormatCatalog();
#pragma warning disable 649
[ImportMany(typeof(ArchiveFormat))]
private IEnumerable<ArchiveFormat> m_arc_formats;
[ImportMany(typeof(ImageFormat))]
private IEnumerable<ImageFormat> m_image_formats;
[ImportMany(typeof(ScriptFormat))]
private IEnumerable<ScriptFormat> m_script_formats;
#pragma warning restore 649
private MultiValueDictionary<string, IResource> m_extension_map = new MultiValueDictionary<string, IResource>();
private MultiValueDictionary<uint, IResource> m_signature_map = new MultiValueDictionary<uint, IResource>();
/// <summary> The only instance of this class.</summary>
public static FormatCatalog Instance { get { return m_instance; } }
public IEnumerable<ArchiveFormat> ArcFormats { get { return m_arc_formats; } }
public IEnumerable<ImageFormat> ImageFormats { get { return m_image_formats; } }
public IEnumerable<ScriptFormat> ScriptFormats { get { return m_script_formats; } }
public Exception LastError { get; set; }
public event ParametersRequestEventHandler ParametersRequest;
private FormatCatalog ()
{
//An aggregate catalog that combines multiple catalogs
var catalog = new AggregateCatalog();
//Adds all the parts found in the same assembly as the Program class
catalog.Catalogs.Add (new AssemblyCatalog (typeof(FormatCatalog).Assembly));
//Adds parts matching pattern found in the directory of the assembly
catalog.Catalogs.Add (new DirectoryCatalog (Path.GetDirectoryName (System.Reflection.Assembly.GetExecutingAssembly().Location), "Arc*.dll"));
//Create the CompositionContainer with the parts in the catalog
var container = new CompositionContainer (catalog);
//Fill the imports of this object
container.ComposeParts (this);
AddResourceImpl (m_arc_formats);
AddResourceImpl (m_image_formats);
AddResourceImpl (m_script_formats);
}
private void AddResourceImpl (IEnumerable<IResource> formats)
{
foreach (var impl in formats)
{
foreach (var ext in impl.Extensions)
{
m_extension_map.Add (ext.ToUpper(), impl);
}
foreach (var signature in impl.Signatures)
{
m_signature_map.Add (signature, impl);
}
}
}
/// <summary>
/// Look up filename in format registry by filename extension and return corresponding interfaces.
/// if no formats available, return empty range.
/// </summary>
public IEnumerable<IResource> LookupFileName (string filename)
{
string ext = Path.GetExtension (filename);
if (null == ext)
return new IResource[0];
return LookupTag (ext.TrimStart ('.'));
}
public IEnumerable<IResource> LookupTag (string tag)
{
return m_extension_map.GetValues (tag.ToUpper(), true);
}
public IEnumerable<Type> LookupTag<Type> (string tag) where Type : IResource
{
return LookupTag (tag).OfType<Type>();
}
public IEnumerable<IResource> LookupSignature (uint signature)
{
return m_signature_map.GetValues (signature, true);
}
public IEnumerable<Type> LookupSignature<Type> (uint signature) where Type : IResource
{
return LookupSignature (signature).OfType<Type>();
}
/// <summary>
/// Create GameRes.Entry corresponding to <paramref name="filename"/> extension.
/// </summary>
public Entry CreateEntry (string filename)
{
Entry entry = null;
string ext = Path.GetExtension (filename);
if (null != ext)
{
ext = ext.TrimStart ('.').ToUpper();
var range = m_extension_map.GetValues (ext, false);
if (null != range)
entry = range.First().CreateEntry();
}
if (null == entry)
entry = new Entry();
entry.Name = filename;
return entry;
}
public string GetTypeFromName (string filename)
{
var formats = LookupFileName (filename);
if (formats.Any())
return formats.First().Type;
return "";
}
public void InvokeParametersRequest (object source, ParametersRequestEventArgs args)
{
if (null != ParametersRequest)
ParametersRequest (source, args);
}
/// <summary>
/// Read first 4 bytes from stream and return them as 32-bit signature.
/// </summary>
public static uint ReadSignature (Stream file)
{
file.Position = 0;
uint signature = (byte)file.ReadByte();
if (BitConverter.IsLittleEndian)
{
signature |= (uint)file.ReadByte() << 8;
signature |= (uint)file.ReadByte() << 16;
signature |= (uint)file.ReadByte() << 24;
}
else
{
signature <<= 24;
signature |= (uint)file.ReadByte() << 16;
signature |= (uint)file.ReadByte() << 8;
signature |= (byte)file.ReadByte();
}
return signature;
}
}
public class InvalidFormatException : Exception
{
public InvalidFormatException() : base(garStrings.MsgInvalidFormat) { }
public InvalidFormatException (string msg) : base (msg) { }
}
public class UnknownEncryptionScheme : Exception
{
public UnknownEncryptionScheme() : base(garStrings.MsgUnknownEncryption) { }
public UnknownEncryptionScheme (string msg) : base (msg) { }
}
public class InvalidEncryptionScheme : Exception
{
public InvalidEncryptionScheme() : base(garStrings.MsgInvalidEncryption) { }
public InvalidEncryptionScheme (string msg) : base (msg) { }
}
}

89
GameRes/GameRes.csproj Normal file
View File

@ -0,0 +1,89 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{453C087F-E416-4AE9-8C03-D8760DA0574B}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>GameRes</RootNamespace>
<AssemblyName>GameRes</AssemblyName>
<TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>..\bin\Release\</OutputPath>
<DefineConstants>
</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<Reference Include="PresentationCore" />
<Reference Include="System" />
<Reference Include="System.ComponentModel.Composition" />
<Reference Include="System.Core" />
<Reference Include="System.Xaml" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
<Reference Include="WindowsBase" />
</ItemGroup>
<ItemGroup>
<Compile Include="ArcFile.cs" />
<Compile Include="ArcView.cs" />
<Compile Include="GameRes.cs" />
<Compile Include="Image.cs" />
<Compile Include="ImageBMP.cs" />
<Compile Include="ImageJPEG.cs" />
<Compile Include="ImagePNG.cs" />
<Compile Include="ImageTGA.cs" />
<Compile Include="ImageTIFF.cs" />
<Compile Include="MultiDict.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ScriptText.cs" />
<Compile Include="Strings\garStrings.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>garStrings.resx</DependentUpon>
</Compile>
<Compile Include="Utility.cs" />
</ItemGroup>
<ItemGroup>
<WCFMetadata Include="Service References\" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Strings\garStrings.resx">
<Generator>PublicResXFileCodeGenerator</Generator>
<LastGenOutput>garStrings.Designer.cs</LastGenOutput>
</EmbeddedResource>
<EmbeddedResource Include="Strings\garStrings.ru-RU.resx" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

100
GameRes/Image.cs Normal file
View File

@ -0,0 +1,100 @@
//! \file Image.cs
//! \date Tue Jul 01 11:29:52 2014
//! \brief image class.
//
using System.IO;
using System.Windows.Media.Imaging;
namespace GameRes
{
public class ImageMetaData
{
public uint Width { get; set; }
public uint Height { get; set; }
public int OffsetX { get; set; }
public int OffsetY { get; set; }
public int BPP { get; set; }
}
public class ImageEntry : Entry
{
public override string Type { get { return "image"; } }
/*
public ImageEntry ()
{
Type = "image";
}
*/
}
public class ImageData
{
private BitmapSource m_bitmap;
public BitmapSource Bitmap { get { return m_bitmap; } }
public uint Width { get { return (uint)m_bitmap.PixelWidth; } }
public uint Height { get { return (uint)m_bitmap.PixelHeight; } }
public int OffsetX { get; set; }
public int OffsetY { get; set; }
public int BPP { get { return m_bitmap.Format.BitsPerPixel; } }
public ImageData (BitmapSource data, ImageMetaData meta)
{
m_bitmap = data;
OffsetX = meta.OffsetX;
OffsetY = meta.OffsetY;
}
public ImageData (BitmapSource data, int x = 0, int y = 0)
{
m_bitmap = data;
OffsetX = x;
OffsetY = y;
}
}
public abstract class ImageFormat : IResource
{
public override string Type { get { return "image"; } }
public ImageData Read (Stream file)
{
bool need_dispose = false;
try
{
if (!file.CanSeek)
{
var stream = new MemoryStream();
file.CopyTo (stream);
file = stream;
need_dispose = true;
}
var info = ReadMetaData (file);
if (null == info)
throw new InvalidFormatException();
return Read (file, info);
}
finally
{
if (need_dispose)
file.Dispose();
}
}
public abstract ImageData Read (Stream file, ImageMetaData info);
public abstract void Write (Stream file, ImageData bitmap);
public abstract ImageMetaData ReadMetaData (Stream file);
public override Entry CreateEntry ()
{
return new ImageEntry();
}
public bool IsBuiltin
{
get { return this.GetType().Assembly == typeof(ImageFormat).Assembly; }
}
}
}

81
GameRes/ImageBMP.cs Normal file
View File

@ -0,0 +1,81 @@
//! \file ImageBMP.cs
//! \date Wed Jul 16 18:06:47 2014
//! \brief BMP image implementation.
//
using System.IO;
using System.Linq;
using System.Text;
using System.ComponentModel.Composition;
using System.Windows.Media.Imaging;
using GameRes.Utility;
using System.Windows.Media;
namespace GameRes
{
[Export(typeof(ImageFormat))]
public class BmpFormat : ImageFormat
{
public override string Tag { get { return "BMP"; } }
public override string Description { get { return "Windows device independent bitmap"; } }
public override uint Signature { get { return 0; } }
public override ImageData Read (Stream file, ImageMetaData info)
{
var decoder = new BmpBitmapDecoder (file,
BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
BitmapSource frame = decoder.Frames.First();
frame.Freeze();
return new ImageData (frame, info);
}
public override void Write (Stream file, ImageData image)
{
var encoder = new BmpBitmapEncoder();
encoder.Frames.Add (BitmapFrame.Create (image.Bitmap));
encoder.Save (file);
}
void SkipBytes (BinaryReader file, uint num)
{
if (file.BaseStream.CanSeek)
file.BaseStream.Seek (num, SeekOrigin.Current);
else
{
for (int i = 0; i < num / 4; ++i)
file.ReadInt32();
for (int i = 0; i < num % 4; ++i)
file.ReadByte();
}
}
public override ImageMetaData ReadMetaData (Stream stream)
{
int c1 = stream.ReadByte();
int c2 = stream.ReadByte();
if (0x42 != c1 || 0x4d != c2)
return null;
using (var file = new ArcView.Reader (stream))
{
uint size = file.ReadUInt32();
if (size < 14+40)
return null;
SkipBytes (file, 8);
uint header_size = file.ReadUInt32();
if (header_size < 40 || size-14 < header_size)
return null;
uint width = file.ReadUInt32();
uint height = file.ReadUInt32();
file.ReadInt16();
int bpp = file.ReadInt16();
return new ImageMetaData {
Width = width,
Height = height,
OffsetX = 0,
OffsetY = 0,
BPP = bpp
};
}
}
}
}

79
GameRes/ImageJPEG.cs Normal file
View File

@ -0,0 +1,79 @@
//! \file ImageJPEG.cs
//! \date Thu Jul 17 15:56:27 2014
//! \brief JPEG image implementation.
//
using System;
using System.IO;
using System.Text;
using System.ComponentModel.Composition;
using System.Windows.Media.Imaging;
using GameRes.Utility;
namespace GameRes
{
[Export(typeof(ImageFormat))]
public class JpegFormat : ImageFormat
{
public override string Tag { get { return "JPEG"; } }
public override string Description { get { return "JPEG image file format"; } }
public override uint Signature { get { return 0; } }
public int Quality { get; set; }
public JpegFormat ()
{
Extensions = new string[] { "jpg", "jpeg" };
Quality = 90;
}
public override ImageData Read (Stream file, ImageMetaData info)
{
var decoder = new JpegBitmapDecoder (file,
BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
var frame = decoder.Frames[0];
frame.Freeze();
return new ImageData (frame, info);
}
public override void Write (Stream file, ImageData image)
{
var encoder = new JpegBitmapEncoder();
encoder.QualityLevel = Quality;
encoder.Frames.Add (BitmapFrame.Create (image.Bitmap));
encoder.Save (file);
}
public override ImageMetaData ReadMetaData (Stream stream)
{
if (0xff != stream.ReadByte() || 0xd8 != stream.ReadByte())
return null;
using (var file = new ArcView.Reader (stream))
{
while (-1 != file.PeekChar())
{
ushort marker = Binary.BigEndian (file.ReadUInt16());
if ((marker & 0xff00) != 0xff00)
break;
int length = Binary.BigEndian (file.ReadUInt16());
if ((marker & 0x00f0) == 0xc0 && marker != 0xffc4)
{
if (length < 8)
break;
int bits = file.ReadByte();
uint height = Binary.BigEndian (file.ReadUInt16());
uint width = Binary.BigEndian (file.ReadUInt16());
int components = file.ReadByte();
return new ImageMetaData {
Width = width,
Height = height,
BPP = bits * components,
};
}
file.BaseStream.Seek (length-2, SeekOrigin.Current);
}
return null;
}
}
}
}

195
GameRes/ImagePNG.cs Normal file
View File

@ -0,0 +1,195 @@
//! \file ImagePNG.cs
//! \date Sat Jul 05 00:09:15 2014
//! \brief PNG image implementation.
//
using System.IO;
using System.Linq;
using System.Text;
using System.ComponentModel.Composition;
using System.Windows.Media.Imaging;
using GameRes.Utility;
using System.Windows.Media;
namespace GameRes
{
[Export(typeof(ImageFormat))]
public class PngFormat : ImageFormat
{
public override string Tag { get { return "PNG"; } }
public override string Description { get { return "Portable Network Graphics image"; } }
public override uint Signature { get { return 0x474e5089; } }
public override ImageData Read (Stream file, ImageMetaData info)
{
var decoder = new PngBitmapDecoder (file,
BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
BitmapSource frame = decoder.Frames.First();
frame.Freeze();
return new ImageData (frame, info);
}
public override void Write (Stream file, ImageData image)
{
var encoder = new PngBitmapEncoder();
encoder.Frames.Add (BitmapFrame.Create (image.Bitmap));
if (0 == image.OffsetX && 0 == image.OffsetY)
{
encoder.Save (file);
return;
}
using (var mem_stream = new MemoryStream())
{
encoder.Save (mem_stream);
byte[] buf = mem_stream.GetBuffer();
long header_pos = 8;
mem_stream.Position = header_pos;
uint header_length = ReadChunkLength (mem_stream);
file.Write (buf, 0, (int)(header_pos+header_length+12));
WriteOffsChunk (file, image);
mem_stream.Position = header_pos+header_length+12;
mem_stream.CopyTo (file);
}
}
uint ReadChunkLength (Stream file)
{
int length = file.ReadByte() << 24;
length |= file.ReadByte() << 16;
length |= file.ReadByte() << 8;
length |= file.ReadByte();
return (uint)length;
}
void WriteOffsChunk (Stream file, ImageData image)
{
using (var membuf = new MemoryStream (32))
{
using (var bin = new BinaryWriter (membuf, Encoding.ASCII, true))
{
bin.Write (Binary.BigEndian ((uint)9));
char[] tag = { 'o', 'F', 'F', 's' };
bin.Write (tag);
bin.Write (Binary.BigEndian ((uint)image.OffsetX));
bin.Write (Binary.BigEndian ((uint)image.OffsetY));
bin.Write ((byte)0);
bin.Flush();
uint crc = Crc32.Compute (membuf.GetBuffer(), 8, 9);
bin.Write (Binary.BigEndian (crc));
}
file.Write (membuf.GetBuffer(), 0, 9+12); // chunk + size+id+crc
}
}
void SkipBytes (BinaryReader file, uint num)
{
if (file.BaseStream.CanSeek)
file.BaseStream.Seek (num, SeekOrigin.Current);
else
{
for (int i = 0; i < num / 4; ++i)
file.ReadInt32();
for (int i = 0; i < num % 4; ++i)
file.ReadByte();
}
}
public override ImageMetaData ReadMetaData (Stream stream)
{
ImageMetaData meta = null;
var file = new ArcView.Reader (stream);
try
{
if (file.ReadUInt32() != Signature)
return null;
if (file.ReadUInt32() != 0x0a1a0a0d)
return null;
uint chunk_size = Binary.BigEndian (file.ReadUInt32());
char[] chunk_type = new char[4];
file.Read (chunk_type, 0, 4);
if (!chunk_type.SequenceEqual ("IHDR"))
return null;
meta = new ImageMetaData();
meta.Width = Binary.BigEndian (file.ReadUInt32());
meta.Height = Binary.BigEndian (file.ReadUInt32());
int bpp = file.ReadByte();
int color_type = file.ReadByte();
switch (color_type)
{
case 2: meta.BPP = bpp*3; break;
case 3: meta.BPP = 24; break;
case 4: meta.BPP = bpp*2; break;
case 6: meta.BPP = bpp*4; break;
default: meta.BPP = bpp; break;
}
SkipBytes (file, 7);
for (;;)
{
chunk_size = Binary.BigEndian (file.ReadUInt32());
file.Read (chunk_type, 0, 4);
if (chunk_type.SequenceEqual ("IDAT") || chunk_type.SequenceEqual ("IEND"))
break;
if (chunk_type.SequenceEqual ("oFFs"))
{
int x = Binary.BigEndian (file.ReadInt32());
int y = Binary.BigEndian (file.ReadInt32());
if (0 == file.ReadByte())
{
meta.OffsetX = x;
meta.OffsetY = y;
}
break;
}
SkipBytes (file, chunk_size+4);
}
}
catch
{
meta = null;
}
finally
{
file.Dispose();
if (stream.CanSeek)
stream.Position = 0;
}
return meta;
}
long FindChunk (Stream stream, string chunk)
{
char[] find_name = chunk.ToCharArray();
long found_offset = -1;
var file = new ArcView.Reader (stream);
try
{
char[] buf = new char[4];
file.BaseStream.Position = 8;
while (-1 != file.PeekChar())
{
long chunk_offset = file.BaseStream.Position;
uint chunk_size = Binary.BigEndian (file.ReadUInt32());
if (4 != file.Read (buf, 0, 4))
break;
if (chunk.SequenceEqual (buf))
{
found_offset = chunk_offset;
break;
}
file.BaseStream.Position += chunk_size + 4;
}
}
catch
{
// ignore errors
}
finally
{
file.Dispose();
}
return found_offset;
}
}
}

204
GameRes/ImageTGA.cs Normal file
View File

@ -0,0 +1,204 @@
//! \file ImageTGA.cs
//! \date Fri Jul 04 07:24:38 2014
//! \brief Targa image implementation.
//
using System.IO;
using System.Text;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.ComponentModel.Composition;
namespace GameRes
{
public class TgaMetaData : ImageMetaData
{
public short ImageType;
public short ColormapType;
public uint ColormapOffset;
public ushort ColormapFirst;
public ushort ColormapLength;
public short ColormapDepth;
public short Descriptor;
}
[Export(typeof(ImageFormat))]
public class TgaFormat : ImageFormat
{
public override string Tag { get { return "TGA"; } }
public override string Description { get { return "Truevision TGA image"; } }
public override uint Signature { get { return 0; } }
public override ImageData Read (Stream stream, ImageMetaData metadata)
{
var meta = metadata as TgaMetaData;
if (null == meta)
throw new System.ArgumentException ("TgaFormat.Read should be supplied with TgaMetaData", "metadata");
int colormap_size = meta.ColormapLength * meta.ColormapDepth / 8;
int width = (int)meta.Width;
int height = (int)meta.Height;
int bpp = meta.BPP;
long image_offset = meta.ColormapOffset;
if (1 == meta.ColormapType)
image_offset += colormap_size;
switch (meta.ImageType)
{
case 1: // Uncompressed, color-mapped images.
case 3: // Uncompressed, black and white images.
case 9: // Runlength encoded color-mapped images.
case 10: // Runlength encoded RGB images.
case 11: // Compressed, black and white images.
case 32: // Compressed color-mapped data, using Huffman, Delta, and
// runlength encoding.
case 33: // Compressed color-mapped data, using Huffman, Delta, and
// runlength encoding. 4-pass quadtree-type process.
throw new System.NotImplementedException();
default:
throw new InvalidFormatException();
case 2: // Uncompressed, RGB images.
{
PixelFormat pixel_format;
switch (bpp)
{
default: throw new InvalidFormatException();
case 24: pixel_format = PixelFormats.Bgr24; break;
case 32: pixel_format = PixelFormats.Bgra32; break;
case 15: pixel_format = PixelFormats.Bgr555; break;
case 16: pixel_format = PixelFormats.Bgr565; break;
}
stream.Position = image_offset;
int stride = width*((bpp+7)/8);
byte[] data = new byte[stride*height];
if (0 != (meta.Descriptor & 0x20))
{
if (data.Length != stream.Read (data, 0, data.Length))
throw new InvalidFormatException();
}
else
{
for (int row = height-1; row >= 0; --row)
{
if (stride != stream.Read (data, row*stride, stride))
throw new InvalidFormatException();
}
}
var bitmap = BitmapSource.Create (width, height, 96, 96, pixel_format, null,
data, stride);
bitmap.Freeze();
return new ImageData (bitmap, meta);
}
throw new InvalidFormatException();
}
}
public override void Write (Stream stream, ImageData image)
{
using (var file = new BinaryWriter (stream, System.Text.Encoding.ASCII, true))
{
file.Write ((byte)0); // idlength
file.Write ((byte)0); // colourmaptype
file.Write ((byte)2); // datatypecode
file.Write ((short)0); // colourmaporigin
file.Write ((short)0); // colourmaplength
file.Write ((byte)0); // colourmapdepth
file.Write ((short)image.OffsetX);
file.Write ((short)image.OffsetY);
file.Write ((ushort)image.Width);
file.Write ((ushort)image.Height);
var bitmap = image.Bitmap;
int bpp = 0;
int stride = 0;
byte descriptor = 0;
if (PixelFormats.Bgr24 == bitmap.Format)
{
bpp = 24;
stride = (int)image.Width*3;
}
else if (PixelFormats.Bgr32 == bitmap.Format)
{
bpp = 32;
stride = (int)image.Width*4;
}
else
{
bpp = 32;
stride = (int)image.Width*4;
if (PixelFormats.Bgra32 != bitmap.Format)
{
var converted_bitmap = new FormatConvertedBitmap();
converted_bitmap.BeginInit();
converted_bitmap.Source = image.Bitmap;
converted_bitmap.DestinationFormat = PixelFormats.Bgra32;
converted_bitmap.EndInit();
bitmap = converted_bitmap;
}
}
file.Write ((byte)bpp);
file.Write (descriptor);
byte[] row_data = new byte[stride];
Int32Rect rect = new Int32Rect (0, (int)image.Height, (int)image.Width, 1);
for (uint row = 0; row < image.Height; ++row)
{
--rect.Y;
bitmap.CopyPixels (rect, row_data, stride, 0);
file.Write (row_data);
}
}
}
public override ImageMetaData ReadMetaData (Stream stream)
{
using (var file = new ArcView.Reader (stream))
{
short id_length = file.ReadByte();
short colormap_type = file.ReadByte();
if (colormap_type > 1)
return null;
short image_type = file.ReadByte();
ushort colormap_first = file.ReadUInt16();
ushort colormap_length = file.ReadUInt16();
short colormap_depth = file.ReadByte();
int pos_x = file.ReadInt16();
int pos_y = file.ReadInt16();
uint width = file.ReadUInt16();
uint height = file.ReadUInt16();
int bpp = file.ReadByte();
if (bpp != 32 && bpp != 24 && bpp != 16 && bpp != 15 && bpp != 8)
return null;
short descriptor = file.ReadByte();
uint colormap_offset = (uint)(18 + id_length);
switch (image_type)
{
default: return null;
case 1: // Uncompressed, color-mapped images.
case 2: // Uncompressed, RGB images.
case 3: // Uncompressed, black and white images.
case 9: // Runlength encoded color-mapped images.
case 10: // Runlength encoded RGB images.
case 11: // Compressed, black and white images.
case 32: // Compressed color-mapped data, using Huffman, Delta, and
// runlength encoding.
case 33: // Compressed color-mapped data, using Huffman, Delta, and
// runlength encoding. 4-pass quadtree-type process.
break;
}
return new TgaMetaData {
OffsetX = pos_x,
OffsetY = pos_y,
Width = width,
Height = height,
BPP = bpp,
ImageType = image_type,
ColormapType = colormap_type,
ColormapOffset = colormap_offset,
ColormapFirst = colormap_first,
ColormapLength = colormap_length,
ColormapDepth = colormap_depth,
Descriptor = descriptor,
};
}
}
}
}

363
GameRes/ImageTIFF.cs Normal file
View File

@ -0,0 +1,363 @@
//! \file ImageTIFF.cs
//! \date Mon Jul 07 06:39:45 2014
//! \brief TIFF image implementation.
//
using System;
using System.IO;
using System.Text;
using System.ComponentModel.Composition;
using System.Windows.Media.Imaging;
using GameRes.Utility;
namespace GameRes
{
#if DEBUG
// FIXME
// .Net TIFF encoder messes up transparency,
// therefore this class is disabled in release build
[Export(typeof(ImageFormat))]
#endif
public class TifFormat : ImageFormat
{
public override string Tag { get { return "TIFF"; } }
public override string Description { get { return "Tagged Image File Format"; } }
public override uint Signature { get { return 0; } }
public TifFormat ()
{
Extensions = new string[] { "tif", "tiff" };
Signatures = new uint[] { 0x002a4949, 0x2a004d4d };
}
public override ImageData Read (Stream file, ImageMetaData info)
{
var decoder = new TiffBitmapDecoder (file,
BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad);
var frame = decoder.Frames[0];
frame.Freeze();
return new ImageData (frame, info);
}
public override void Write (Stream file, ImageData image)
{
var encoder = new TiffBitmapEncoder();
encoder.Compression = TiffCompressOption.Zip;
encoder.Frames.Add (BitmapFrame.Create (image.Bitmap));
encoder.Save (file);
}
private delegate uint UInt32Reader();
private delegate ushort UInt16Reader();
enum TIFF
{
ImageWidth = 0x100,
ImageHeight = 0x101,
BitsPerSample = 0x102,
Compression = 0x103,
SamplesPerPixel = 0x115,
XResolution = 0x11a,
YResolution = 0x11b,
XPosition = 0x11e,
YPosition = 0x11f,
}
enum TagType
{
Byte = 1,
Ascii = 2,
Short = 3,
Long = 4,
Rational = 5,
SByte = 6,
Undefined = 7,
SShort = 8,
SLong = 9,
SRational = 10,
Float = 11,
Double = 12,
LastKnown = Double,
}
enum MetaParsed
{
None = 0,
Width = 1,
Height = 2,
BPP = 4,
PosX = 8,
PosY = 16,
Sufficient = Width|Height|BPP,
Complete = Sufficient|PosX|PosY,
}
public override ImageMetaData ReadMetaData (Stream stream)
{
using (var file = new Parser (stream))
return file.ReadMetaData();
}
public class Parser : IDisposable
{
private BinaryReader m_file;
private readonly bool m_is_bigendian;
private readonly uint m_first_ifd;
private readonly uint[] m_type_size = { 0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8 };
private delegate ushort UInt16Reader ();
private delegate uint UInt32Reader ();
private delegate ulong UInt64Reader ();
UInt16Reader ReadUInt16;
UInt32Reader ReadUInt32;
UInt64Reader ReadUInt64;
public Parser (Stream file)
{
m_file = new ArcView.Reader (file);
uint signature = m_file.ReadUInt32();
m_is_bigendian = 0x2a004d4d == signature;
if (m_is_bigendian)
{
ReadUInt16 = () => Binary.BigEndian (m_file.ReadUInt16());
ReadUInt32 = () => Binary.BigEndian (m_file.ReadUInt32());
ReadUInt64 = () => Binary.BigEndian (m_file.ReadUInt64());
}
else
{
ReadUInt16 = () => m_file.ReadUInt16();
ReadUInt32 = () => m_file.ReadUInt32();
ReadUInt64 = () => m_file.ReadUInt64();
}
m_first_ifd = ReadUInt32();
}
public long FindLastIFD ()
{
uint ifd = m_first_ifd;
for (;;)
{
m_file.BaseStream.Position = ifd;
uint tag_count = ReadUInt16();
ifd += 2 + tag_count*12;
uint ifd_next = ReadUInt32();
if (0 == ifd_next)
break;
if (ifd_next == ifd || ifd_next >= m_file.BaseStream.Length)
return -1;
ifd = ifd_next;
}
return ifd;
}
public ImageMetaData ReadMetaData ()
{
MetaParsed parsed = MetaParsed.None;
int width = 0, height = 0, bpp = 0, pos_x = 0, pos_y = 0;
uint ifd = m_first_ifd;
while (ifd != 0 && parsed != MetaParsed.Complete)
{
m_file.BaseStream.Position = ifd;
uint tag_count = ReadUInt16();
ifd += 2;
for (uint i = 0; i < tag_count && parsed != MetaParsed.Complete; ++i)
{
ushort tag = ReadUInt16();
TagType type = (TagType)ReadUInt16();
uint count = ReadUInt32();
if (0 != count && 0 != type && type <= TagType.LastKnown)
{
switch ((TIFF)tag)
{
case TIFF.ImageWidth:
if (1 == count)
if (ReadOffsetValue (type, out width))
parsed |= MetaParsed.Width;
break;
case TIFF.ImageHeight:
if (1 == count)
if (ReadOffsetValue (type, out height))
parsed |= MetaParsed.Height;
break;
case TIFF.XPosition:
if (1 == count)
if (ReadOffsetValue (type, out pos_x))
parsed |= MetaParsed.PosX;
break;
case TIFF.YPosition:
if (1 == count)
if (ReadOffsetValue (type, out pos_y))
parsed |= MetaParsed.PosY;
break;
case TIFF.BitsPerSample:
if (count * GetTypeSize (type) > 4)
{
var bpp_offset = ReadUInt32();
m_file.BaseStream.Position = bpp_offset;
}
bpp = 0;
for (uint b = 0; b < count; ++b)
{
int plane = 0;
ReadValue (type, out plane);
bpp += plane;
}
parsed |= MetaParsed.BPP;
break;
default:
break;
}
}
ifd += 12;
m_file.BaseStream.Position = ifd;
}
uint ifd_next = ReadUInt32();
if (ifd_next == ifd)
break;
ifd = ifd_next;
}
if (MetaParsed.Sufficient == (parsed & MetaParsed.Sufficient))
return new ImageMetaData() {
Width = (uint)width,
Height = (uint)height,
OffsetX = pos_x,
OffsetY = pos_y,
BPP = bpp,
};
else
return null;
}
uint GetTypeSize (TagType type)
{
if ((int)type < m_type_size.Length)
return m_type_size[(int)type];
else
return 0;
}
bool ReadOffsetValue (TagType type, out int value)
{
if (GetTypeSize (type) > 4)
m_file.BaseStream.Position = ReadUInt32();
return ReadValue (type, out value);
}
bool ReadValue (TagType type, out int value)
{
switch (type)
{
case TagType.Undefined:
case TagType.SByte:
case TagType.Byte:
value = m_file.ReadByte();
break;
default:
case TagType.Ascii:
value = 0;
return false;
case TagType.SShort:
case TagType.Short:
value = ReadUInt16();
break;
case TagType.SLong:
case TagType.Long:
value = (int)ReadUInt32();
break;
case TagType.Rational:
return ReadRational (out value);
case TagType.SRational:
return ReadSRational (out value);
case TagType.Float:
return ReadFloat (out value);
case TagType.Double:
return ReadDouble (out value);
}
return true;
}
bool ReadRational (out int value)
{
uint numer = ReadUInt32();
uint denom = ReadUInt32();
if (1 == denom)
value = (int)numer;
else if (0 == denom)
{
value = 0;
return false;
}
else
value = (int)((double)numer / denom);
return true;
}
bool ReadSRational (out int value)
{
int numer = (int)ReadUInt32();
int denom = (int)ReadUInt32();
if (1 == denom)
value = numer;
else if (0 == denom)
{
value = 0;
return false;
}
else
value = (int)((double)numer / denom);
return true;
}
bool ReadFloat (out int value)
{
var convert_buffer = new byte[4];
if (4 != m_file.Read (convert_buffer, 0, 4))
{
value = 0;
return false;
}
if (m_is_bigendian)
Array.Reverse (convert_buffer);
value = (int)BitConverter.ToSingle (convert_buffer, 0);
return true;
}
bool ReadDouble (out int value)
{
var convert_buffer = new byte[8];
if (8 != m_file.Read (convert_buffer, 0, 8))
{
value = 0;
return false;
}
if (m_is_bigendian)
Array.Reverse (convert_buffer);
long bits = BitConverter.ToInt64 (convert_buffer, 0);
value = (int)BitConverter.Int64BitsToDouble (bits);
return true;
}
#region IDisposable Members
bool disposed = false;
public void Dispose ()
{
Dispose (true);
GC.SuppressFinalize (this);
}
protected virtual void Dispose (bool disposing)
{
if (!disposed)
{
if (disposing)
{
m_file.Dispose();
}
m_file = null;
disposed = true;
}
}
#endregion
}
}
}

162
GameRes/MultiDict.cs Normal file
View File

@ -0,0 +1,162 @@
//! \file GameRes.cs
//! \date Mon Jun 30 20:12:13 2014
//! \brief game resources browser.
//
using System;
using System.Collections.Generic;
namespace GameRes.Collections
{
/// <summary>
/// Extension to the normal Dictionary. This class can store more than one value for every key.
/// It keeps a HashSet for every Key value. Calling Add with the same Key and multiple values
/// will store each value under the same Key in the Dictionary. Obtaining the values for a Key
/// will return the HashSet with the Values of the Key.
/// </summary>
/// <typeparam name="TKey">The type of the key.</typeparam>
/// <typeparam name="TValue">The type of the value.</typeparam>
public class MultiValueDictionary<TKey, TValue> : Dictionary<TKey, HashSet<TValue>> //, IEnumerable<KeyValuePair<TKey, TValue>>, System.Collections.IEnumerable
{
/// <summary>
/// Initializes a new instance of the <see cref="MultiValueDictionary&lt;TKey, TValue&gt;"/> class.
/// </summary>
public MultiValueDictionary() : base()
{
}
/// <summary>
/// Adds the specified value under the specified key
/// </summary>
/// <param name="key">The key.</param>
/// <param name="value">The value.</param>
public void Add(TKey key, TValue value)
{
HashSet<TValue> container = null;
if(!this.TryGetValue(key, out container))
{
container = new HashSet<TValue>();
base.Add(key, container);
}
container.Add(value);
}
/// <summary>
/// Removes the specified value for the specified key. It will leave the key in the dictionary.
/// </summary>
/// <param name="key">The key.</param>
/// <param name="value">The value.</param>
public void Remove(TKey key, TValue value)
{
HashSet<TValue> container = null;
if(this.TryGetValue(key, out container))
{
container.Remove(value);
if(container.Count <= 0)
{
this.Remove(key);
}
}
}
/// <summary>
/// Gets the values for the key specified. This method is useful if you want to avoid an
/// exception for key value retrieval and you can't use TryGetValue (e.g. in lambdas)
/// </summary>
/// <param name="key">The key.</param>
/// <param name="returnEmptySet">if set to true and the key isn't found, an empty hashset is
/// returned, otherwise, if the key isn't found, null is returned</param>
/// <returns>
/// This method will return null (or an empty set if returnEmptySet is true) if the key
/// wasn't found, or the values if key was found.
/// </returns>
public HashSet<TValue> GetValues(TKey key, bool returnEmptySet)
{
HashSet<TValue> toReturn = null;
if (!base.TryGetValue(key, out toReturn) && returnEmptySet)
{
toReturn = new HashSet<TValue>();
}
return toReturn;
}
/*
// hides Dictionary.GetEnumerator()
new public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
Enumerator e = new Enumerator();
e.key_enumerator = base.GetEnumerator();
e.current_pair = new KeyValuePair<TKey, TValue>();
if (e.key_enumerator.MoveNext())
e.value_enumerator = e.key_enumerator.Current.Value.GetEnumerator();
else
e.value_enumerator = null;
return e;
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return (System.Collections.IEnumerator)GetEnumerator();
}
[SerializableAttribute]
new public struct Enumerator : IEnumerator<KeyValuePair<TKey, TValue>>, IDisposable, System.Collections.IEnumerator
{
public Dictionary<TKey, HashSet<TValue>>.Enumerator key_enumerator;
public HashSet<TValue>.Enumerator? value_enumerator;
public KeyValuePair<TKey, TValue> current_pair;
public KeyValuePair<TKey, TValue> Current { get { return current_pair; } }
object System.Collections.IEnumerator.Current { get { return Current; } }
void IDisposable.Dispose() { }
void System.Collections.IEnumerator.Reset()
{
}
private void SetCurrent ()
{
current_pair = new KeyValuePair<TKey, TValue>(key_enumerator.Current.Key, value_enumerator.Value.Current);
Console.WriteLine("Enumerator.SetCurrent ({0} => {1})", current_pair.Key, current_pair.Value);
}
private void ResetCurrent ()
{
current_pair = new KeyValuePair<TKey, TValue>(default(TKey), default(TValue));
}
public bool MoveNext ()
{
if (null == value_enumerator)
{
ResetCurrent();
return false;
}
if (value_enumerator.Value.MoveNext())
{
SetCurrent();
return true;
}
if (!key_enumerator.MoveNext())
{
value_enumerator = null;
ResetCurrent();
return false;
}
value_enumerator = key_enumerator.Current.Value.GetEnumerator();
if (value_enumerator.Value.MoveNext())
{
SetCurrent();
return true;
}
else
{
current_pair = new KeyValuePair<TKey, TValue>(key_enumerator.Current.Key, default(TValue));
return false;
}
}
}
*/
}
}

View File

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("GameRes")]
[assembly: AssemblyDescription("Game Resources class library")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("GameRes")]
[assembly: AssemblyCopyright("Copyright © 2014 mørkt")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("224080ad-deb6-4d47-a454-903a14c74cb7")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// 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.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

36
GameRes/ScriptText.cs Normal file
View File

@ -0,0 +1,36 @@
//! \file ScriptText.cs
//! \date Thu Jul 10 11:09:32 2014
//! \brief Script text resource interface.
//
using System.IO;
using System.Text;
using System.Collections.Generic;
namespace GameRes
{
public struct ScriptLine
{
public uint Id;
public string Text;
}
public class ScriptData
{
public ICollection<ScriptLine> TextLines { get { return m_text; } }
protected List<ScriptLine> m_text = new List<ScriptLine>();
/*
public abstract void Serialize (Stream output);
public abstract void Deserialize (Stream input);
*/
}
public abstract class ScriptFormat : IResource
{
public override string Type { get { return "script"; } }
public abstract ScriptData Read (string name, Stream file);
public abstract void Write (Stream file, ScriptData script);
}
}

90
GameRes/Strings/garStrings.Designer.cs generated Normal file
View File

@ -0,0 +1,90 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.18444
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace GameRes.Strings {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
public class garStrings {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal garStrings() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("GameRes.Strings.garStrings", typeof(garStrings).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized string similar to Inappropriate encryption scheme.
/// </summary>
public static string MsgInvalidEncryption {
get {
return ResourceManager.GetString("MsgInvalidEncryption", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Invalid file format.
/// </summary>
public static string MsgInvalidFormat {
get {
return ResourceManager.GetString("MsgInvalidFormat", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Unknown encryption scheme.
/// </summary>
public static string MsgUnknownEncryption {
get {
return ResourceManager.GetString("MsgUnknownEncryption", resourceCulture);
}
}
}
}

View File

@ -0,0 +1,129 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="MsgInvalidEncryption" xml:space="preserve">
<value>Inappropriate encryption scheme</value>
</data>
<data name="MsgInvalidFormat" xml:space="preserve">
<value>Invalid file format</value>
</data>
<data name="MsgUnknownEncryption" xml:space="preserve">
<value>Unknown encryption scheme</value>
</data>
</root>

View File

@ -0,0 +1,129 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="MsgInvalidEncryption" xml:space="preserve">
<value>Неподходящий метод шифрования</value>
</data>
<data name="MsgInvalidFormat" xml:space="preserve">
<value>Некорректный формат файла</value>
</data>
<data name="MsgUnknownEncryption" xml:space="preserve">
<value>Неизвестный метод шифрования</value>
</data>
</root>

235
GameRes/Utility.cs Normal file
View File

@ -0,0 +1,235 @@
//! \file Utility.cs
//! \date Sat Jul 05 02:47:33 2014
//! \brief utility class for GameRes assembly.
//
namespace GameRes.Utility
{
public static class Binary
{
public static uint BigEndian (uint u)
{
return (u & 0xff) << 24 | (u & 0xff00) << 8 | (u & 0xff0000) >> 8 | (u & 0xff000000) >> 24;
}
public static int BigEndian (int i)
{
return (int)BigEndian ((uint)i);
}
public static ushort BigEndian (ushort u)
{
return (ushort)((u & 0xff) << 8 | (u & 0xff00) >> 8);
}
public static short BigEndian (short i)
{
return (short)BigEndian ((ushort)i);
}
public static ulong BigEndian (ulong u)
{
return (ulong)BigEndian((uint)(u & 0xffffffff)) << 32
| (ulong)BigEndian((uint)(u >> 32));
}
public static long BigEndian (long i)
{
return (long)BigEndian ((ulong)i);
}
public static bool AsciiEqual (byte[] name1, string name2)
{
return AsciiEqual (name1, 0, name2);
}
public static bool AsciiEqual (byte[] name1, int offset, string name2)
{
if (name1.Length-offset < name2.Length)
return false;
for (int i = 0; i < name2.Length; ++i)
if ((char)name1[offset+i] != name2[i])
return false;
return true;
}
}
public static class LittleEndian
{
public static ushort ToUInt16 (byte[] value, int index)
{
return (ushort)(value[index] | value[index+1] << 8);
}
public static short ToInt16 (byte[] value, int index)
{
return (short)(value[index] | value[index+1] << 8);
}
public static uint ToUInt32 (byte[] value, int index)
{
return (uint)(value[index] | value[index+1] << 8 | value[index+2] << 16 | value[index+3] << 24);
}
public static int ToInt32 (byte[] value, int index)
{
return (int)ToUInt32 (value, index);
}
}
public sealed class Crc32
{
/* Table of CRCs of all 8-bit messages. */
private static readonly uint[] crc_table = InitializeTable();
/* Make the table for a fast CRC. */
private static uint[] InitializeTable ()
{
uint[] table = new uint[256];
for (uint n = 0; n < 256; n++)
{
uint c = n;
for (int k = 0; k < 8; k++)
{
if (0 != (c & 1))
c = 0xedb88320 ^ (c >> 1);
else
c = c >> 1;
}
table[n] = c;
}
return table;
}
/* Update a running CRC with the bytes buf[0..len-1]--the CRC
should be initialized to all 1's, and the transmitted value
is the 1's complement of the final running CRC (see the
crc() routine below)). */
static uint UpdateCrc (uint crc, byte[] buf, int pos, int len)
{
uint c = crc;
for (int n = 0; n < len; n++)
c = crc_table[(c ^ buf[pos+n]) & 0xff] ^ (c >> 8);
return c;
}
/* Return the CRC of the bytes buf[0..len-1]. */
public static uint Compute (byte[] buf, int pos, int len)
{
return UpdateCrc (0xffffffff, buf, pos, len) ^ 0xffffffff;
}
private uint m_crc = 0xffffffff;
public uint Value { get { return m_crc^0xffffffff; } }
public void Update (byte[] buf, int pos, int len)
{
m_crc = UpdateCrc (m_crc, buf, pos, len);
}
}
public sealed class Adler32
{
const uint BASE = 65521; /* largest prime smaller than 65536 */
const int NMAX = 5552;
public static uint Compute (byte[] buf, int pos, int len)
{
return Update (1, buf, pos, len);
}
private static uint Update (uint adler, byte[] buf, int pos, int len)
{
/* split Adler-32 into component sums */
uint sum2 = (adler >> 16) & 0xffff;
adler &= 0xffff;
/* in case user likes doing a byte at a time, keep it fast */
if (1 == len) {
adler += buf[pos];
if (adler >= BASE)
adler -= BASE;
sum2 += adler;
if (sum2 >= BASE)
sum2 -= BASE;
return adler | (sum2 << 16);
}
/* in case short lengths are provided, keep it somewhat fast */
if (len < 16) {
while (0 != len--) {
adler += buf[pos++];
sum2 += adler;
}
if (adler >= BASE)
adler -= BASE;
sum2 %= BASE; /* only added so many BASE's */
return adler | (sum2 << 16);
}
/* do length NMAX blocks -- requires just one modulo operation */
while (len >= NMAX) {
len -= NMAX;
int n = NMAX / 16; /* NMAX is divisible by 16 */
do {
/* 16 sums unrolled */
adler += buf[pos]; sum2 += adler;
adler += buf[pos+1]; sum2 += adler;
adler += buf[pos+2]; sum2 += adler;
adler += buf[pos+3]; sum2 += adler;
adler += buf[pos+4]; sum2 += adler;
adler += buf[pos+5]; sum2 += adler;
adler += buf[pos+6]; sum2 += adler;
adler += buf[pos+7]; sum2 += adler;
adler += buf[pos+8]; sum2 += adler;
adler += buf[pos+9]; sum2 += adler;
adler += buf[pos+10]; sum2 += adler;
adler += buf[pos+11]; sum2 += adler;
adler += buf[pos+12]; sum2 += adler;
adler += buf[pos+13]; sum2 += adler;
adler += buf[pos+14]; sum2 += adler;
adler += buf[pos+15]; sum2 += adler;
pos += 16;
} while (0 != --n);
adler %= BASE;
sum2 %= BASE;
}
/* do remaining bytes (less than NMAX, still just one modulo) */
if (0 != len) { /* avoid modulos if none remaining */
while (len >= 16) {
len -= 16;
adler += buf[pos]; sum2 += adler;
adler += buf[pos+1]; sum2 += adler;
adler += buf[pos+2]; sum2 += adler;
adler += buf[pos+3]; sum2 += adler;
adler += buf[pos+4]; sum2 += adler;
adler += buf[pos+5]; sum2 += adler;
adler += buf[pos+6]; sum2 += adler;
adler += buf[pos+7]; sum2 += adler;
adler += buf[pos+8]; sum2 += adler;
adler += buf[pos+9]; sum2 += adler;
adler += buf[pos+10]; sum2 += adler;
adler += buf[pos+11]; sum2 += adler;
adler += buf[pos+12]; sum2 += adler;
adler += buf[pos+13]; sum2 += adler;
adler += buf[pos+14]; sum2 += adler;
adler += buf[pos+15]; sum2 += adler;
pos += 16;
}
while (0 != len--) {
adler += buf[pos++];
sum2 += adler;
}
adler %= BASE;
sum2 %= BASE;
}
/* return recombined sums */
return adler | (sum2 << 16);
}
private uint m_adler = 1;
public uint Value { get { return m_adler; } }
public void Update (byte[] buf, int pos, int len)
{
m_adler = Update (m_adler, buf, pos, len);
}
}
}

109
HistoryStack.cs Normal file
View File

@ -0,0 +1,109 @@
//! \file HistoryStack.cs
//! \date Sun Aug 21 01:06:53 2011
//! \brief action history stack interface (undo/redo).
//
// Copyright (C) 2011 by poddav
//
// 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.Collections.Generic;
using System.Linq;
namespace Rnd.Windows
{
public class HistoryStack<State>
{
private List<State> m_back = new List<State>();
private Stack<State> m_forward = new Stack<State>();
public int Limit { get; set; }
public IEnumerable<State> UndoStack { get { return m_back; } }
public IEnumerable<State> RedoStack { get { return m_forward; } }
public HistoryStack (int limit = 50)
{
Limit = limit;
}
public State Undo (State current)
{
if (!CanUndo())
return default(State);
m_forward.Push (current);
current = m_back.Last();
m_back.RemoveAt (m_back.Count - 1);
OnStateChanged();
return current;
}
public State Redo (State current)
{
if (!CanRedo())
return default(State);
m_back.Add (current);
current = m_forward.Pop();
OnStateChanged();
return current;
}
public bool CanUndo ()
{
return m_back.Any();
}
public bool CanRedo ()
{
return m_forward.Any();
}
public void Push (State current)
{
m_back.Add (current);
if (m_back.Count > Limit)
m_back.RemoveRange (0, m_back.Count - Limit);
m_forward.Clear();
OnStateChanged();
}
public void Clear ()
{
if (m_back.Any() || m_forward.Any())
{
m_back.Clear();
m_forward.Clear();
OnStateChanged();
}
}
public event EventHandler StateChanged;
private void OnStateChanged ()
{
if (StateChanged != null)
StateChanged (this, EventArgs.Empty);
}
}
}

6
Image.Convert/App.config Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.1"/>
</startup>
</configuration>

View File

@ -0,0 +1,70 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{757EB8B1-F62C-4690-AC3D-DAE4A5576B3E}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Image.Convert</RootNamespace>
<AssemblyName>Image.Convert</AssemblyName>
<TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>..\bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup>
<NoWin32Manifest>true</NoWin32Manifest>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\GameRes\GameRes.csproj">
<Project>{453c087f-e416-4ae9-8c03-d8760da0574b}</Project>
<Name>GameRes</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'">
<StartArguments>-t tga uninstall.hg3</StartArguments>
</PropertyGroup>
</Project>

174
Image.Convert/Program.cs Normal file
View File

@ -0,0 +1,174 @@
using System;
using System.IO;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using GameRes;
namespace GARbro
{
class ImageConverter
{
static string ProgramName
{
get
{
return Path.GetFileNameWithoutExtension(System.Reflection.Assembly.GetExecutingAssembly().Location);
}
}
void Usage ()
{
Console.WriteLine("Usage: {0} [OPTIONS] IMAGE", ProgramName);
Console.WriteLine(" -l list recognized image FormatCatalog.Instance");
Console.WriteLine(" -t FORMAT convert image(s) to specified format");
Console.WriteLine("Without options image metadata is displayed.");
}
void ListFormats ()
{
Console.WriteLine("Supported image formats:");
foreach (var impl in FormatCatalog.Instance.ImageFormats)
{
Console.Write ("{0,-4} ", impl.Tag);
if (impl.IsBuiltin) Console.Write ("[builtin] ");
Console.WriteLine (impl.Description);
}
}
ImageFormat FindFormat (string format)
{
var range = FormatCatalog.Instance.LookupTag<ImageFormat> (format);
return range.FirstOrDefault();
}
Tuple<ImageFormat, ImageMetaData> FindImageFormat (ArcView arc)
{
uint signature = arc.View.ReadUInt32 (0);
using (var stream = arc.CreateStream())
{
for (;;)
{
var range = FormatCatalog.Instance.LookupSignature<ImageFormat> (signature);
foreach (var impl in range)
{
try
{
ImageMetaData metadata = impl.ReadMetaData (stream);
if (null != metadata)
return new Tuple<ImageFormat, ImageMetaData> (impl, metadata);
stream.Position = 0;
}
catch { }
}
if (0 == signature)
break;
signature = 0;
}
}
return null;
}
ImageData ReadImage (ArcView file)
{
var format = FindImageFormat (file);
if (null == format)
return null;
using (var stream = file.CreateStream())
return format.Item1.Read (stream, format.Item2);
}
void PrintMetaData (string filename)
{
using (ArcView file = new ArcView (filename))
{
var format = FindImageFormat (file);
if (null == format)
{
Console.Error.WriteLine ("{0}: file format not recognized", filename);
return;
}
var image = format.Item2;
Console.WriteLine ("{0,16} [{4}] {1}x{2} {3}bpp", filename, image.Width, image.Height, image.BPP, format.Item1.Tag);
}
}
void ConvertFile (string filename, ImageFormat format)
{
ImageData image;
using (var file = new ArcView (filename))
{
image = ReadImage (file);
if (null == image)
{
Console.Error.WriteLine ("{0}: Unknown image format", filename);
return;
}
}
string target_ext = format.Extensions.First();
string outname = Path.GetFileNameWithoutExtension (filename)+'.'+target_ext;
Console.WriteLine ("{0} => {1}", filename, outname);
using (var outfile = new FileStream (outname, FileMode.Create, FileAccess.Write))
{
format.Write (outfile, image);
}
}
void Run (string[] args)
{
if (args.Length < 1 || args[0] == "/?" || args[0] == "--help")
{
Usage();
}
else if (args[0] == "-l")
{
ListFormats();
}
else if (args[0] == "-t")
{
if (args.Length < 3)
{
Usage();
return;
}
ImageFormat format = FindFormat (args[1]);
if (null == format)
{
Console.Error.WriteLine ("{0}: unknown format specified", args[1]);
return;
}
for (int i = 2; i < args.Length; ++i)
{
try
{
ConvertFile (args[i], format);
}
catch (Exception X)
{
Console.Error.WriteLine ("{0}: {1}", args[i], X.Message);
}
}
}
else
{
foreach (var filename in args)
{
PrintMetaData (filename);
}
}
}
static void Main(string[] args)
{
try
{
var program = new ImageConverter();
program.Run (args);
}
catch (Exception X)
{
Console.Error.WriteLine ("{0}: {1}", ProgramName, X.Message);
}
}
}
}

View File

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Image.Convert")]
[assembly: AssemblyDescription("Image Conversion utility")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Image.Convert")]
[assembly: AssemblyCopyright("Copyright © 2014 mørkt")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("5becba95-6a61-452a-8075-9b523494cc09")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// 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.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

205
ImagePreview.cs Normal file
View File

@ -0,0 +1,205 @@
//! \file ImagePreview.cs
//! \date Sun Jul 06 06:34:56 2014
//! \brief preview images.
//
using System;
using System.IO;
using System.Linq;
using System.Collections.Generic;
using System.Diagnostics;
using System.ComponentModel;
using System.Windows;
using System.Windows.Media.Imaging;
using GARbro.GUI.Strings;
using GameRes;
namespace GARbro.GUI
{
public partial class MainWindow : Window
{
private readonly BackgroundWorker m_preview_worker = new BackgroundWorker();
private PreviewFile m_current_preview = new PreviewFile();
private bool m_preview_pending = false;
class PreviewFile
{
public string Path { get; set; }
public string Name { get; set; }
public Entry Entry { get; set; }
public ArcFile Archive { get; set; }
public bool IsEqual (string path, string name)
{
return path.Equals (Path) && name.Equals (Name);
}
}
private void InitPreviewPane ()
{
m_preview_worker.DoWork += (s, e) => LoadPreviewImage (e.Argument as PreviewFile);
m_preview_worker.RunWorkerCompleted += (s, e) => {
if (m_preview_pending)
RefreshPreviewPane();
};
}
/// <summary>
/// Display entry in preview panel
/// </summary>
private void PreviewEntry (Entry entry)
{
if (m_current_preview.IsEqual (ViewModel.Path, entry.Name))
return;
UpdatePreviewPane (entry);
}
void RefreshPreviewPane ()
{
m_preview_pending = false;
var current = CurrentDirectory.SelectedItem as EntryViewModel;
if (null != current)
UpdatePreviewPane (current.Source);
else
PreviewPane.Source = null;
}
void UpdatePreviewPane (Entry entry)
{
SetStatusText ("");
var vm = ViewModel;
m_current_preview = new PreviewFile { Path = vm.Path, Name = entry.Name };
PreviewPane.Source = null;
if (entry.Type != "image")
return;
if (vm.IsArchive)
{
m_current_preview.Archive = m_app.CurrentArchive;
m_current_preview.Entry = entry;
}
if (!m_preview_worker.IsBusy)
m_preview_worker.RunWorkerAsync (m_current_preview);
else
m_preview_pending = true;
}
void LoadPreviewImage (PreviewFile preview)
{
try
{
Stream file;
if (null == preview.Archive)
{
string filename = Path.Combine (preview.Path, preview.Name);
file = new FileStream (filename, FileMode.Open, FileAccess.Read);
}
else
{
file = preview.Archive.OpenEntry (preview.Entry);
}
using (file)
{
var data = ReadImage (file);
if (null != data)
SetPreviewImage (preview, data.Bitmap);
else
Trace.WriteLine ("Cannot parse image format", preview.Name);
}
}
catch (Exception X)
{
SetStatusText (X.Message);
}
}
void SetPreviewImage (PreviewFile preview, BitmapSource bitmap)
{
if (bitmap.DpiX != Desktop.DpiX || bitmap.DpiY != Desktop.DpiY)
{
int stride = bitmap.PixelWidth * ((bitmap.Format.BitsPerPixel + 7) / 8);
var pixels = new byte[stride*bitmap.PixelHeight];
bitmap.CopyPixels (pixels, stride, 0);
var fixed_bitmap = BitmapSource.Create (bitmap.PixelWidth, bitmap.PixelHeight,
Desktop.DpiX, Desktop.DpiY, bitmap.Format, bitmap.Palette, pixels, stride);
bitmap = fixed_bitmap;
}
if (!bitmap.IsFrozen)
bitmap.Freeze();
Dispatcher.Invoke (() =>
{
if (m_current_preview == preview) // compare by reference
{
PreviewPane.Source = bitmap;
SetStatusText (string.Format ("Image {0} x {1} x {2}bpp", bitmap.PixelWidth,
bitmap.PixelHeight, bitmap.Format.BitsPerPixel));
}
});
}
ImageData ReadImage (Stream file)
{
bool need_dispose = false;
try
{
if (!file.CanSeek)
{
var stream = new MemoryStream();
file.CopyTo (stream);
file = stream;
need_dispose = true;
}
var format = FindImageFormat (file);
if (null == format)
return null;
file.Position = 0;
return format.Item1.Read (file, format.Item2);
}
finally
{
if (need_dispose)
file.Dispose();
}
}
Tuple<ImageFormat, ImageMetaData> FindImageFormat (Stream file)
{
uint signature = FormatCatalog.ReadSignature (file);
for (;;)
{
var range = FormatCatalog.Instance.LookupSignature<ImageFormat> (signature);
foreach (var impl in range)
{
try
{
file.Position = 0;
ImageMetaData metadata = impl.ReadMetaData (file);
if (null != metadata)
return new Tuple<ImageFormat, ImageMetaData> (impl, metadata);
}
catch { }
}
if (0 == signature)
break;
signature = 0;
}
return null;
}
void ExtractImage (ArcFile arc, Entry entry, ImageFormat target_format)
{
using (var file = arc.OpenEntry (entry))
{
ImageData image = ReadImage (file);
if (null == image)
throw new InvalidFormatException (string.Format ("{1}: {0}", guiStrings.MsgUnableInterpret, entry.Name));
string target_ext = target_format.Extensions.First();
string outname = Path.GetFileNameWithoutExtension (entry.Name)+'.'+target_ext;
Trace.WriteLine (string.Format ("{0} => {1}", entry.Name, outname), "ExtractFileFromArchive");
using (var outfile = File.Create (outname))
{
target_format.Write (outfile, image);
}
}
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

BIN
Images/32x32/help.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
Images/64x64/info.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

BIN
Images/search4files.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

258
MainWindow.xaml Normal file
View File

@ -0,0 +1,258 @@
<Window x:Class="GARbro.GUI.MainWindow" x:Name="AppWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:GARbro.GUI"
xmlns:s="clr-namespace:GARbro.GUI.Strings"
xmlns:p="clr-namespace:GARbro.GUI.Properties"
xmlns:sdk="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Input.Toolkit"
Title="GARbro" MinHeight="250" ResizeMode="CanResizeWithGrip"
Loaded="WindowLoaded"
Top="{Binding Source={x:Static p:Settings.Default}, Path=winTop, Mode=TwoWay}"
Left="{Binding Source={x:Static p:Settings.Default}, Path=winLeft, Mode=TwoWay}"
Height="{Binding Source={x:Static p:Settings.Default}, Path=winHeight, Mode=TwoWay}"
Width="{Binding Source={x:Static p:Settings.Default}, Path=winWidth, Mode=TwoWay}"
WindowState="{Binding Source={x:Static p:Settings.Default}, Path=winState, Mode=TwoWay}">
<Window.Resources>
<SolidColorBrush x:Key="AlternateColor1" Color="#f2f5f9" />
<SolidColorBrush x:Key="AlternateColor2" Color="White" />
<BitmapImage x:Key="Icon32x32Back" UriSource="Images/32x32/back button.png"/>
<BitmapImage x:Key="Icon32x32Forward" UriSource="Images/32x32/forward button.png"/>
<BitmapImage x:Key="Icon32x32Help" UriSource="Images/32x32/help.png"/>
<CollectionViewSource x:Key="ListViewSource" Source="{Binding}"/>
<Style x:Key="HeaderLeftAlign" TargetType="{x:Type GridViewColumnHeader}">
<Setter Property="HorizontalContentAlignment" Value="Left"></Setter>
</Style>
<DataTemplate x:Key="SortArrowUp">
<DockPanel>
<TextBlock Margin="5,0,5,0" Text="{Binding}" />
<Path VerticalAlignment="Center" Fill="Gray" Data="M 5,5 15,5 10,0 5,5" />
</DockPanel>
</DataTemplate>
<DataTemplate x:Key="SortArrowDown">
<DockPanel>
<TextBlock Margin="5,0,5,0" Text="{Binding}" />
<Path VerticalAlignment="Center" Fill="Gray" Data="M 5,0 10,5 15,0 5,0" />
</DockPanel>
</DataTemplate>
<DataTemplate x:Key="SortArrowNone">
<TextBlock Margin="5,0,5,0" Text="{Binding}"/>
</DataTemplate>
</Window.Resources>
<DockPanel LastChildFill="True">
<Menu x:Name="MainMenuBar" DockPanel.Dock="Top" IsMainMenu="True" Visibility="Collapsed"/>
<DockPanel Background="{Binding Path=Background, ElementName=MainMenuBar}" x:Name="MainToolBar"
HorizontalAlignment="Stretch" DockPanel.Dock="Top">
<DockPanel.Resources>
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource {x:Static ToolBar.ButtonStyleKey}}">
<Setter Property="ToolTipService.ShowOnDisabled" Value="True"/>
<Setter Property="Focusable" Value="False"/>
<Setter Property="Margin" Value="1,2,1,2"/>
</Style>
<Style TargetType="{x:Type ToggleButton}" BasedOn="{StaticResource {x:Static ToolBar.ToggleButtonStyleKey}}">
<Setter Property="ToolTipService.ShowOnDisabled" Value="True"/>
<Setter Property="Focusable" Value="False"/>
<Setter Property="Margin" Value="2,2,2,2"/>
</Style>
<Style TargetType="{x:Type Separator}" BasedOn="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}">
<Setter Property="Margin" Value="5,0,5,0"/>
</Style>
<Style TargetType="{x:Type Image}">
<Setter Property="UseLayoutRounding" Value="True"/>
<Setter Property="SnapsToDevicePixels" Value="True"/>
<!--
<Setter Property="Width" Value="{Binding RelativeSource={RelativeSource Self}, Path=Source.Width}"/>
<Setter Property="Height" Value="{Binding RelativeSource={RelativeSource Self}, Path=Source.Height}"/>
<Setter Property="Stretch" Value="None"/>
-->
<Setter Property="Width" Value="24"/>
<Setter Property="Height" Value="24"/>
<Setter Property="Stretch" Value="Uniform"/>
<!-- hack to make images within disabled toolbar buttons appear 'grayed out'.
This doesn't gray them at all, but lowers their opacity so the (usually gray)
background of the button shows through. If WPF had a built-in facility for
grayscaling images in disabled buttons, this kind of icky kludgery wouldn't be
necessary -->
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType={x:Type Button}, AncestorLevel=1}, Path=IsEnabled}" Value="False">
<Setter Property="Opacity" Value="0.33"/>
</DataTrigger>
</Style.Triggers>
</Style>
</DockPanel.Resources>
<Button x:Name="ButtonBack" ToolTip="{x:Static s:guiStrings.TooltipBack}" Margin="5,2,0,2"
Command="{x:Static local:Commands.GoBack}">
<Image Source="{StaticResource Icon32x32Back}"/>
</Button>
<Button x:Name="ButtonForward" ToolTip="{x:Static s:guiStrings.TooltipForward}"
Command="{x:Static local:Commands.GoForward}">
<Image Source="{StaticResource Icon32x32Forward}"/>
</Button>
<Separator/>
<local:ExtAutoCompleteBox x:Name="pathLine" Height="22" Width="100" KeyDown="acb_OnKeyDown"/>
<Button ToolTip="{x:Static s:guiStrings.MenuAbout}" DockPanel.Dock="Right" Margin="0,2,10,2" Click="MenuAbout_Click">
<Image Source="{StaticResource Icon32x32Help}"/>
</Button>
<TextBlock Visibility="Hidden"/>
</DockPanel>
<StatusBar DockPanel.Dock="Bottom">
<StatusBarItem>
<TextBlock x:Name="appStatusText"/>
</StatusBarItem>
</StatusBar>
<Grid x:Name="ContentGrid" DockPanel.Dock="Left" VerticalAlignment="Stretch"
HorizontalAlignment="Stretch" ShowGridLines="False">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding Source={x:Static p:Settings.Default}, Path=lvPanelWidth, Mode=TwoWay}" MinWidth="200" />
<ColumnDefinition Width="1"/>
<ColumnDefinition Width="*" MinWidth="100"/>
</Grid.ColumnDefinitions>
<ListView Name="CurrentDirectory" Grid.Column="0"
ItemsSource="{Binding Source={StaticResource ListViewSource}}"
VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
BorderBrush="Transparent" SelectedValuePath="Name"
SelectionMode="Extended" Foreground="Black" AlternationCount="2"
PreviewTextInput="lv_TextInput" IsSynchronizedWithCurrentItem="True"
GridViewColumnHeader.Click="lv_ColumnHeaderClicked">
<ListView.Resources>
<SolidColorBrush x:Key="ItemInactiveBackground" Color="#ffcbcbcb" />
<Style x:Key="DefaultMenuItemStyle" TargetType="{x:Type MenuItem}">
<Setter Property="FontWeight" Value="Bold" />
</Style>
<ContextMenu x:Key="lvDirContextMenu">
<MenuItem Header="{x:Static s:guiStrings.CtxMenuOpen}" InputGestureText="Enter"
Style="{StaticResource DefaultMenuItemStyle}"
Command="{x:Static local:Commands.OpenItem}" />
<MenuItem Header="{x:Static s:guiStrings.CtxMenuExtract}" InputGestureText="F4"
Command="{x:Static local:Commands.ExtractItem}" />
<MenuItem Header="{x:Static s:guiStrings.CtxMenuExplorer}" InputGestureText="Ctrl+E"
Command="{x:Static local:Commands.ExploreItem}"/>
<Separator/>
<MenuItem Header="{x:Static s:guiStrings.CtxMenuDelete}" InputGestureText="Del"
Command="{x:Static local:Commands.DeleteItem}"/>
<Separator/>
<!--
<MenuItem Header="{x:Static s:guiStrings.CtxMenuRename}" InputGestureText="F2"
Command="{x:Static local:Commands.RenameItem}"/>
-->
<MenuItem Header="{x:Static s:guiStrings.CtxMenuRefresh}" InputGestureText="F5"
Command="{x:Static local:Commands.Refresh}"/>
<!-- Sort-by submenu
<MenuItem Header="{x:Static s:guiStrings.CtxMenuSortBy}">
<MenuItem Header="{x:Static s:guiStrings.CtxMenuSortByName}" IsCheckable="True"
IsChecked="{Binding ElementName=AppWindow, Path=IsSortByName, Mode=OneWay}"
Command="{x:Static local:Commands.SortBy}" CommandParameter="Name"/>
<MenuItem Header="{x:Static s:guiStrings.CtxMenuSortByType}" IsCheckable="True"
IsChecked="{Binding ElementName=AppWindow, Path=IsSortByType, Mode=OneWay}"
Command="{x:Static local:Commands.SortBy}" CommandParameter="Type"/>
<MenuItem Header="{x:Static s:guiStrings.CtxMenuSortBySize}" IsCheckable="True"
IsChecked="{Binding ElementName=AppWindow, Path=IsSortBySize, Mode=OneWay}"
Command="{x:Static local:Commands.SortBy}" CommandParameter="Size"/>
<MenuItem Header="{x:Static s:guiStrings.CtxMenuUnsorted}" IsCheckable="True"
IsChecked="{Binding ElementName=AppWindow, Path=IsUnsorted, Mode=OneWay}"
Command="{x:Static local:Commands.SortBy}"/>
</MenuItem>
-->
</ContextMenu>
</ListView.Resources>
<ListView.InputBindings>
<KeyBinding Key="Enter" Command="{x:Static local:Commands.OpenItem}"/>
<KeyBinding Gesture="Ctrl+E" Command="{x:Static local:Commands.ExploreItem}"/>
<KeyBinding Gesture="F2" Command="{x:Static local:Commands.RenameItem}"/>
<KeyBinding Gesture="F4" Command="{x:Static local:Commands.ExtractItem}"/>
<KeyBinding Gesture="F5" Command="{x:Static local:Commands.Refresh}"/>
<KeyBinding Gesture="Delete" Command="{x:Static local:Commands.DeleteItem}"/>
<KeyBinding Gesture="Backspace" Command="{x:Static local:Commands.GoBack}"/>
<MouseBinding Gesture="LeftDoubleClick" Command="{x:Static local:Commands.OpenItem}" />
</ListView.InputBindings>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="ContextMenu" Value="{StaticResource lvDirContextMenu}"/>
<EventSetter Event="Selected" Handler="lvi_Selected"/>
<EventSetter Event="ListViewItem.MouseDoubleClick" Handler="lvi_DoubleClick" />
<Style.Triggers>
<!-- BEGIN alternate row color -->
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="False" />
<Condition Property="IsMouseOver" Value="False" />
<Condition Property="ItemsControl.AlternationIndex" Value="0"/>
</MultiTrigger.Conditions>
<Setter Property="Background" Value="{StaticResource AlternateColor1}"/>
</MultiTrigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="False" />
<Condition Property="IsMouseOver" Value="False" />
<Condition Property="ItemsControl.AlternationIndex" Value="1"/>
</MultiTrigger.Conditions>
<Setter Property="Background" Value="{StaticResource AlternateColor2}"/>
</MultiTrigger>
<!-- END alternate row color -->
<!-- BEGIN context menu trigger -->
<!--
<DataTrigger Binding="{Binding Path=IsArchive}" Value="True">
<Setter Property="ContextMenu" Value="{StaticResource lvArcContextMenu}"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=IsArchive}" Value="False">
<Setter Property="ContextMenu" Value="{StaticResource lvDirContextMenu}"/>
</DataTrigger>
-->
<!-- END context menu trigger -->
</Style.Triggers>
</Style>
</ListView.ItemContainerStyle>
<ListView.View>
<GridView AllowsColumnReorder="False">
<GridViewColumn HeaderContainerStyle="{StaticResource HeaderLeftAlign}" Width="{Binding Source={x:Static p:Settings.Default}, Path=lvNameColumnWidth, Mode=TwoWay}" HeaderTemplate="{StaticResource SortArrowNone}">
<GridViewColumn.Header>
<GridViewColumnHeader Tag="Name" Content="{x:Static s:guiStrings.HeaderName}"/>
</GridViewColumn.Header>
<GridViewColumn.CellTemplate>
<DataTemplate><TextBlock x:Name="item_Name" Text="{Binding Path=Name}"/></DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn HeaderContainerStyle="{StaticResource HeaderLeftAlign}" Width="{Binding Source={x:Static p:Settings.Default}, Path=lvTypeColumnWidth, Mode=TwoWay}" HeaderTemplate="{StaticResource SortArrowNone}" DisplayMemberBinding="{Binding Path=Type}">
<GridViewColumn.Header>
<GridViewColumnHeader Tag="Type" Content="{x:Static s:guiStrings.HeaderType}"/>
</GridViewColumn.Header>
</GridViewColumn>
<GridViewColumn HeaderContainerStyle="{StaticResource HeaderLeftAlign}" Width="{Binding Source={x:Static p:Settings.Default}, Path=lvSizeColumnWidth, Mode=TwoWay}" HeaderTemplate="{StaticResource SortArrowNone}">
<GridViewColumn.Header>
<GridViewColumnHeader Tag="Size" Content="{x:Static s:guiStrings.HeaderSize}"/>
</GridViewColumn.Header>
<GridViewColumn.CellTemplate>
<DataTemplate><TextBlock Text="{Binding Path=Size}" TextAlignment="Right"/></DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
<ScrollViewer Grid.Column="2" Background="LightGray"
VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
<Image Name="PreviewPane" Stretch="None" UseLayoutRounding="False" SnapsToDevicePixels="True"
local:TouchScrolling.IsEnabled="True"/>
</ScrollViewer>
<!-- Margin and BorderThickness help to react early on mouse pointer -->
<GridSplitter Grid.Column="1" Background="Black" ShowsPreview="False" Focusable="False"
Margin="-3,0" BorderThickness="3,0" BorderBrush="Transparent"
HorizontalAlignment="Center" VerticalAlignment="Stretch" />
</Grid>
</DockPanel>
<Window.InputBindings>
<KeyBinding Gesture="Ctrl+Q" Command="{x:Static local:Commands.Exit}"/>
<KeyBinding Gesture="Backspace" Command="{x:Static local:Commands.GoBack}"/>
</Window.InputBindings>
<Window.CommandBindings>
<CommandBinding Command="{x:Static local:Commands.OpenItem}" Executed="OpenItemExec" CanExecute="CanExecuteOnSelected"/>
<CommandBinding Command="{x:Static local:Commands.ExtractItem}" Executed="ExtractItemExec" CanExecute="CanExecuteOnSelected"/>
<CommandBinding Command="{x:Static local:Commands.DeleteItem}" Executed="DeleteItemExec" CanExecute="CanExecuteDelete" />
<CommandBinding Command="{x:Static local:Commands.RenameItem}" Executed="RenameItemExec" CanExecute="CanExecuteInDirectory" />
<CommandBinding Command="{x:Static local:Commands.ExploreItem}" Executed="ExploreItemExec" CanExecute="CanExecuteInDirectory" />
<CommandBinding Command="{x:Static local:Commands.SortBy}" Executed="SortByExec" CanExecute="CanExecuteAlways"/>
<CommandBinding Command="{x:Static local:Commands.GoBack}" Executed="GoBackExec" CanExecute="CanExecuteGoBack"/>
<CommandBinding Command="{x:Static local:Commands.GoForward}" Executed="GoForwardExec" CanExecute="CanExecuteGoForward"/>
<CommandBinding Command="{x:Static local:Commands.Refresh}" Executed="RefreshExec" CanExecute="CanExecuteAlways"/>
<CommandBinding Command="{x:Static local:Commands.Exit}" Executed="ExitExec" CanExecute="CanExecuteAlways"/>
</Window.CommandBindings>
</Window>

1094
MainWindow.xaml.cs Normal file

File diff suppressed because it is too large Load Diff

20
Makefile Normal file
View File

@ -0,0 +1,20 @@
MSCS = D:/WINDOWS/Microsoft.NET/Framework/v4.0.30319/csc //nologo
.SUFFIXES: .cs .exe
all: GARbro
adler32: adler32.cs
$(MSCS) $(MSCSFLAGS) //out:$@.exe $^
inflate: inflate.cs
$(MSCS) $(MSCSFLAGS) //out:$@.exe $^ //r:zlib\\zlibnet.dll
deflate: deflate.cs
$(MSCS) $(MSCSFLAGS) //out:$@.exe $^ //r:zlib\\zlibnet.dll
GARbro: Program.cs GameRes.cs ArcXFL.cs
$(MSCS) $(MSCSFLAGS) //out:$@.exe $^ //r:System.ComponentModel.Composition.dll //r:System.ComponentModel.DataAnnotations.dll
tags:
ctags *.cs

88
ModalWindow.cs Normal file
View File

@ -0,0 +1,88 @@
//! \file ModalWindow.cs
//! \date Tue Aug 02 10:20:50 2011
//! \brief Window without an icon.
//
// Copyright (C) 2011 by poddav
//
// 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.Windows;
using System.Windows.Interop;
using System.Runtime.InteropServices;
namespace Rnd.Windows
{
/// <summary>
/// Window without an icon.
/// </summary>
public class ModalWindow : Window
{
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
HideIcon (this);
}
internal class NativeMethods
{
[DllImport ("user32.dll")]
internal static extern int GetWindowLong (IntPtr hwnd, int index);
[DllImport ("user32.dll")]
internal static extern int SetWindowLong (IntPtr hwnd, int index, int newStyle);
[DllImport ("user32.dll")]
internal static extern bool SetWindowPos (IntPtr hwnd, IntPtr hwndInsertAfter, int x, int y, int width, int height, uint flags);
[DllImport ("user32.dll")]
internal static extern IntPtr SendMessage (IntPtr hwnd, uint msg, IntPtr wParam, IntPtr lParam);
}
const int GWL_EXSTYLE = -20;
const int WS_EX_DLGMODALFRAME = 0x0001;
const int SWP_NOSIZE = 0x0001;
const int SWP_NOMOVE = 0x0002;
const int SWP_NOZORDER = 0x0004;
const int SWP_FRAMECHANGED = 0x0020;
const uint WM_SETICON = 0x0080;
/// <summary>
/// Win32 mumbo-jumbo to hide window icon and its menu.
/// </summary>
public static void HideIcon (Window window)
{
// Get this window's handle
IntPtr hwnd = new WindowInteropHelper (window).Handle;
// Change the extended window style to not show a window icon
int extendedStyle = NativeMethods.GetWindowLong (hwnd, GWL_EXSTYLE);
NativeMethods.SetWindowLong (hwnd, GWL_EXSTYLE, extendedStyle | WS_EX_DLGMODALFRAME);
NativeMethods.SendMessage (hwnd, WM_SETICON, IntPtr.Zero, IntPtr.Zero);
NativeMethods.SendMessage (hwnd, WM_SETICON, new IntPtr (1), IntPtr.Zero);
// Update the window's non-client area to reflect the changes
NativeMethods.SetWindowPos (hwnd, IntPtr.Zero, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
}
}
}

View File

@ -0,0 +1,55 @@
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Windows;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Game Resource browser")]
[assembly: AssemblyDescription("Game Resource browser")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("GARbro.GUI")]
[assembly: AssemblyCopyright("Copyright © 2014 mørkt")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
//In order to begin building localizable applications, set
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
//inside a <PropertyGroup>. For example, if you are using US english
//in your source files, set the <UICulture> to en-US. Then uncomment
//the NeutralResourceLanguage attribute below. Update the "en-US" in
//the line below to match the UICulture setting in the project file.
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// 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.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

63
Properties/Resources.Designer.cs generated Normal file
View File

@ -0,0 +1,63 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.18444
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace GARbro.GUI.Properties {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("GARbro.GUI.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
}
}

117
Properties/Resources.resx Normal file
View File

@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

230
Properties/Settings.Designer.cs generated Normal file
View File

@ -0,0 +1,230 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.18444
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace GARbro.GUI.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "12.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
return defaultInstance;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool UpgradeRequired {
get {
return ((bool)(this["UpgradeRequired"]));
}
set {
this["UpgradeRequired"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("NaN")]
public double winTop {
get {
return ((double)(this["winTop"]));
}
set {
this["winTop"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("NaN")]
public double winLeft {
get {
return ((double)(this["winLeft"]));
}
set {
this["winLeft"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("1024")]
public double winWidth {
get {
return ((double)(this["winWidth"]));
}
set {
this["winWidth"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("560")]
public double winHeight {
get {
return ((double)(this["winHeight"]));
}
set {
this["winHeight"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("Normal")]
public global::System.Windows.WindowState winState {
get {
return ((global::System.Windows.WindowState)(this["winState"]));
}
set {
this["winState"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("265")]
public double lvNameColumnWidth {
get {
return ((double)(this["lvNameColumnWidth"]));
}
set {
this["lvNameColumnWidth"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("75")]
public double lvTypeColumnWidth {
get {
return ((double)(this["lvTypeColumnWidth"]));
}
set {
this["lvTypeColumnWidth"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("75")]
public double lvSizeColumnWidth {
get {
return ((double)(this["lvSizeColumnWidth"]));
}
set {
this["lvSizeColumnWidth"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("Name")]
public string lvSortColumn {
get {
return ((string)(this["lvSortColumn"]));
}
set {
this["lvSortColumn"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("Ascending")]
public global::System.ComponentModel.ListSortDirection lvSortDirection {
get {
return ((global::System.ComponentModel.ListSortDirection)(this["lvSortDirection"]));
}
set {
this["lvSortDirection"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("448")]
public global::System.Windows.GridLength lvPanelWidth {
get {
return ((global::System.Windows.GridLength)(this["lvPanelWidth"]));
}
set {
this["lvPanelWidth"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool appExtractImages {
get {
return ((bool)(this["appExtractImages"]));
}
set {
this["appExtractImages"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool appExtractText {
get {
return ((bool)(this["appExtractText"]));
}
set {
this["appExtractText"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
public string appImageFormat {
get {
return ((string)(this["appImageFormat"]));
}
set {
this["appImageFormat"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("UTF-8")]
public string appTextEncoding {
get {
return ((string)(this["appTextEncoding"]));
}
set {
this["appTextEncoding"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
public string appLastDirectory {
get {
return ((string)(this["appLastDirectory"]));
}
set {
this["appLastDirectory"] = value;
}
}
}
}

View File

@ -0,0 +1,57 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="GARbro.GUI.Properties" GeneratedClassName="Settings">
<Profiles />
<Settings>
<Setting Name="UpgradeRequired" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="winTop" Type="System.Double" Scope="User">
<Value Profile="(Default)">NaN</Value>
</Setting>
<Setting Name="winLeft" Type="System.Double" Scope="User">
<Value Profile="(Default)">NaN</Value>
</Setting>
<Setting Name="winWidth" Type="System.Double" Scope="User">
<Value Profile="(Default)">1024</Value>
</Setting>
<Setting Name="winHeight" Type="System.Double" Scope="User">
<Value Profile="(Default)">560</Value>
</Setting>
<Setting Name="winState" Type="System.Windows.WindowState" Scope="User">
<Value Profile="(Default)">Normal</Value>
</Setting>
<Setting Name="lvNameColumnWidth" Type="System.Double" Scope="User">
<Value Profile="(Default)">265</Value>
</Setting>
<Setting Name="lvTypeColumnWidth" Type="System.Double" Scope="User">
<Value Profile="(Default)">75</Value>
</Setting>
<Setting Name="lvSizeColumnWidth" Type="System.Double" Scope="User">
<Value Profile="(Default)">75</Value>
</Setting>
<Setting Name="lvSortColumn" Type="System.String" Scope="User">
<Value Profile="(Default)">Name</Value>
</Setting>
<Setting Name="lvSortDirection" Type="System.ComponentModel.ListSortDirection" Scope="User">
<Value Profile="(Default)">Ascending</Value>
</Setting>
<Setting Name="lvPanelWidth" Type="System.Windows.GridLength" Scope="User">
<Value Profile="(Default)">448</Value>
</Setting>
<Setting Name="appExtractImages" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="appExtractText" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="appImageFormat" Type="System.String" Scope="User">
<Value Profile="(Default)" />
</Setting>
<Setting Name="appTextEncoding" Type="System.String" Scope="User">
<Value Profile="(Default)">UTF-8</Value>
</Setting>
<Setting Name="appLastDirectory" Type="System.String" Scope="User">
<Value Profile="(Default)" />
</Setting>
</Settings>
</SettingsFile>

54
Properties/app.manifest Normal file
View File

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<asmv1:assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<assemblyIdentity version="1.0.0.0" name="MyApplication.app" />
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<!-- UAC Manifest Options
If you want to change the Windows User Account Control level replace the
requestedExecutionLevel node with one of the following.
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
<requestedExecutionLevel level="highestAvailable" uiAccess="false" />
Specifying requestedExecutionLevel node will disable file and registry virtualization.
If you want to utilize File and Registry Virtualization for backward
compatibility then delete the requestedExecutionLevel node.
-->
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
</requestedPrivileges>
<applicationRequestMinimum>
<defaultAssemblyRequest permissionSetReference="Custom" />
<PermissionSet class="System.Security.PermissionSet" version="1" ID="Custom" SameSite="site" Unrestricted="true" />
</applicationRequestMinimum>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- A list of all Windows versions that this application is designed to work with.
Windows will automatically select the most compatible environment.-->
<!-- If your application is designed to work with Windows Vista, uncomment the following supportedOS node-->
<!--<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"></supportedOS>-->
<!-- If your application is designed to work with Windows 7, uncomment the following supportedOS node-->
<!--<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>-->
<!-- If your application is designed to work with Windows 8, uncomment the following supportedOS node-->
<!--<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"></supportedOS>-->
<!-- If your application is designed to work with Windows 8.1, uncomment the following supportedOS node-->
<!--<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>-->
</application>
</compatibility>
<!-- Enable themes for Windows common controls and dialogs (Windows XP and later) -->
<!-- <dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="*"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>-->
</asmv1:assembly>

43
Settings.cs Normal file
View File

@ -0,0 +1,43 @@
namespace GARbro.GUI.Properties {
// This class allows you to handle specific events on the settings class:
// The SettingChanging event is raised before a setting's value is changed.
// The PropertyChanged event is raised after a setting's value is changed.
// The SettingsLoaded event is raised after the setting values are loaded.
// The SettingsSaving event is raised before the setting values are saved.
internal sealed partial class Settings {
public Settings() {
// // To add event handlers for saving and changing settings, uncomment the lines below:
//
// this.SettingChanging += this.SettingChangingEventHandler;
//
// this.SettingsSaving += this.SettingsSavingEventHandler;
//
this.SettingsLoaded += OnSettingsLoadedHandler;
}
void OnSettingsLoadedHandler (object sender, System.Configuration.SettingsLoadedEventArgs e)
{
if (Settings.Default.UpgradeRequired)
{
Settings.Default.Upgrade();
Settings.Default.UpgradeRequired = false;
Settings.Default.Save();
// do not restore in minimized state
if (Settings.Default.winState == System.Windows.WindowState.Minimized)
Settings.Default.winState = System.Windows.WindowState.Normal;
}
}
private void SettingChangingEventHandler(object sender, System.Configuration.SettingChangingEventArgs e) {
// Add code to handle the SettingChangingEvent event here.
}
private void SettingsSavingEventHandler(object sender, System.ComponentModel.CancelEventArgs e) {
// Add code to handle the SettingsSaving event here.
}
}
}

182
Shell.cs Normal file
View File

@ -0,0 +1,182 @@
//! \file Shell.cs
//! \date Tue Aug 02 13:48:55 2011
//! \brief Win32 shell functions.
//
// Copyright (C) 2011 by poddav
//
// 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.Text;
using System.Runtime.InteropServices;
namespace Rnd.Shell
{
/// <summary>
/// Wrapper around PathCreateFromUrl WINAPI call.
/// </summary>
class PathConverter
{
[DllImport("shlwapi.dll", EntryPoint="PathCreateFromUrlW", CharSet=CharSet.Unicode, SetLastError=true)]
private static extern Int32 PathCreateFromUrl(
string url, StringBuilder path,
ref Int32 size, UInt32 flags);
private StringBuilder buf;
private Int32 size;
public PathConverter (int capacity = 260)
{
buf = new StringBuilder (capacity);
}
public string UrlToPath (string url)
{
size = buf.Capacity;
Int32 rc = PathCreateFromUrl (url, buf, ref size, 0);
return rc == 0 ? buf.ToString (0, size) : "";
}
}
/// <summary>
/// Wrapper around SHGetFileInfo WINAPI call.
/// </summary>
class FileInfo
{
[DllImport("shell32.dll", CharSet=CharSet.Auto)]
public static extern IntPtr SHGetFileInfo(
string pszPath, Int32 dwFileAttributes,
ref SHFILEINFO psfi, int cbFileInfo, int uFlags);
[DllImport("User32.dll")]
public static extern int DestroyIcon(IntPtr hIcon);
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
public struct SHFILEINFO
{
public IntPtr hIcon;
public int iIcon;
public uint dwAttributes;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string szDisplayName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
public string szTypeName;
public SHFILEINFO(bool b)
{
hIcon = IntPtr.Zero;
iIcon = 0;
dwAttributes = 0;
szDisplayName = "";
szTypeName = "";
}
};
[Flags]
public enum SHGFI : uint
{
/// <summary>get icon</summary>
Icon = 0x000000100,
/// <summary>get display name</summary>
DisplayName = 0x000000200,
/// <summary>get type name</summary>
TypeName = 0x000000400,
/// <summary>get attributes</summary>
Attributes = 0x000000800,
/// <summary>get icon location</summary>
IconLocation = 0x000001000,
/// <summary>return exe type</summary>
ExeType = 0x000002000,
/// <summary>get system icon index</summary>
SysIconIndex = 0x000004000,
/// <summary>put a link overlay on icon</summary>
LinkOverlay = 0x000008000,
/// <summary>show icon in selected state</summary>
Selected = 0x000010000,
/// <summary>get only specified attributes</summary>
Attr_Specified = 0x000020000,
/// <summary>get large icon</summary>
LargeIcon = 0x000000000,
/// <summary>get small icon</summary>
SmallIcon = 0x000000001,
/// <summary>get open icon</summary>
OpenIcon = 0x000000002,
/// <summary>get shell size icon</summary>
ShellIconSize = 0x000000004,
/// <summary>pszPath is a pidl</summary>
PIDL = 0x000000008,
/// <summary>use passed dwFileAttribute</summary>
UseFileAttributes= 0x000000010,
/// <summary>apply the appropriate overlays</summary>
AddOverlays = 0x000000020,
/// <summary>Get the index of the overlay in the upper 8 bits of the iIcon</summary>
OverlayIndex = 0x000000040,
}
public static string GetTypeName (string filename)
{
SHFILEINFO info = new SHFILEINFO(true);
int szInfo = Marshal.SizeOf (info);
int result = (int)SHGetFileInfo (filename, 0, ref info, szInfo, (int)SHGFI.TypeName);
// If uFlags does not contain SHGFI_EXETYPE or SHGFI_SYSICONINDEX,
// the return value is nonzero if successful, or zero otherwise.
if (result != 0)
return info.szTypeName;
else
return string.Empty;
}
public static SHFILEINFO? GetInfo (string filename, SHGFI flags)
{
SHFILEINFO info = new SHFILEINFO(true);
int szInfo = Marshal.SizeOf (info);
int result = (int)SHGetFileInfo (filename, 0, ref info, szInfo, (int)flags);
return result != 0? new Nullable<SHFILEINFO> (info): null;
}
}
/// <summary>
/// Wrapper around MoveFileEx WINAPI call.
/// </summary>
class File
{
[DllImport("kernel32.dll", EntryPoint="MoveFileExW", SetLastError=true, CharSet=CharSet.Unicode)]
public static extern bool MoveFileEx (string lpExistingFileName, string lpNewFileName, MoveFileFlags dwFlags);
[Flags]
public enum MoveFileFlags : uint
{
ReplaceExisting = 0x00000001,
CopyAllowed = 0x00000002,
DelayUntilReboot = 0x00000004,
WriteThrough = 0x00000008,
CreateHardlink = 0x00000010,
FailIfNotTrackable = 0x00000020
}
public static bool Rename (string szFrom, string szTo)
{
return MoveFileEx (szFrom, szTo, MoveFileFlags.ReplaceExisting);
}
}
}

594
Strings/guiStrings.Designer.cs generated Normal file
View File

@ -0,0 +1,594 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.18444
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace GARbro.GUI.Strings {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
public class guiStrings {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal guiStrings() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("GARbro.GUI.Strings.guiStrings", typeof(guiStrings).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized string similar to Cancel.
/// </summary>
public static string ButtonCancel {
get {
return ResourceManager.GetString("ButtonCancel", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Extract.
/// </summary>
public static string ButtonExtract {
get {
return ResourceManager.GetString("ButtonExtract", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to OK.
/// </summary>
public static string ButtonOK {
get {
return ResourceManager.GetString("ButtonOK", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to _Close.
/// </summary>
public static string CtxMenuClose {
get {
return ResourceManager.GetString("CtxMenuClose", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Copy.
/// </summary>
public static string CtxMenuCopy {
get {
return ResourceManager.GetString("CtxMenuCopy", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Cut.
/// </summary>
public static string CtxMenuCut {
get {
return ResourceManager.GetString("CtxMenuCut", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to _Delete.
/// </summary>
public static string CtxMenuDelete {
get {
return ResourceManager.GetString("CtxMenuDelete", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Browse in _Explorer.
/// </summary>
public static string CtxMenuExplorer {
get {
return ResourceManager.GetString("CtxMenuExplorer", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Extract.
/// </summary>
public static string CtxMenuExtract {
get {
return ResourceManager.GetString("CtxMenuExtract", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Open.
/// </summary>
public static string CtxMenuOpen {
get {
return ResourceManager.GetString("CtxMenuOpen", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Paste.
/// </summary>
public static string CtxMenuPaste {
get {
return ResourceManager.GetString("CtxMenuPaste", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Refresh.
/// </summary>
public static string CtxMenuRefresh {
get {
return ResourceManager.GetString("CtxMenuRefresh", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to _Rename.
/// </summary>
public static string CtxMenuRename {
get {
return ResourceManager.GetString("CtxMenuRename", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Sort by.
/// </summary>
public static string CtxMenuSortBy {
get {
return ResourceManager.GetString("CtxMenuSortBy", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Name.
/// </summary>
public static string CtxMenuSortByName {
get {
return ResourceManager.GetString("CtxMenuSortByName", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Size.
/// </summary>
public static string CtxMenuSortBySize {
get {
return ResourceManager.GetString("CtxMenuSortBySize", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Type.
/// </summary>
public static string CtxMenuSortByType {
get {
return ResourceManager.GetString("CtxMenuSortByType", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Unsorted.
/// </summary>
public static string CtxMenuUnsorted {
get {
return ResourceManager.GetString("CtxMenuUnsorted", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Name.
/// </summary>
public static string HeaderName {
get {
return ResourceManager.GetString("HeaderName", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Size.
/// </summary>
public static string HeaderSize {
get {
return ResourceManager.GetString("HeaderSize", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Type.
/// </summary>
public static string HeaderType {
get {
return ResourceManager.GetString("HeaderType", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to file.
/// </summary>
public static string LPfile1 {
get {
return ResourceManager.GetString("LPfile1", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to files.
/// </summary>
public static string LPfile2 {
get {
return ResourceManager.GetString("LPfile2", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to About.
/// </summary>
public static string MenuAbout {
get {
return ResourceManager.GetString("MenuAbout", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Deleted {0}.
/// </summary>
public static string MsgDeletedItem {
get {
return ResourceManager.GetString("MsgDeletedItem", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to directory not found.
/// </summary>
public static string MsgDirectoryNotFound {
get {
return ResourceManager.GetString("MsgDirectoryNotFound", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to archive is empty.
/// </summary>
public static string MsgEmptyArchive {
get {
return ResourceManager.GetString("MsgEmptyArchive", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Error extracting file.
/// </summary>
public static string MsgErrorExtracting {
get {
return ResourceManager.GetString("MsgErrorExtracting", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Error opening file.
/// </summary>
public static string MsgErrorOpening {
get {
return ResourceManager.GetString("MsgErrorOpening", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Extracted {0} into {1}.
/// </summary>
public static string MsgExtractComplete {
get {
return ResourceManager.GetString("MsgExtractComplete", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Extracted {0} {1}.
/// </summary>
public static string MsgExtractCompletePlural {
get {
return ResourceManager.GetString("MsgExtractCompletePlural", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Extracting files from {0}.
/// </summary>
public static string MsgExtractingArchive {
get {
return ResourceManager.GetString("MsgExtractingArchive", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Extracting file from {0}.
/// </summary>
public static string MsgExtractingFile {
get {
return ResourceManager.GetString("MsgExtractingFile", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Extracting files from {0} to {1}.
/// </summary>
public static string MsgExtractingTo {
get {
return ResourceManager.GetString("MsgExtractingTo", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Image {0} x {1} pixels.
/// </summary>
public static string MsgImageSize {
get {
return ResourceManager.GetString("MsgImageSize", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to no files to extract.
/// </summary>
public static string MsgNoFiles {
get {
return ResourceManager.GetString("MsgNoFiles", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Ready.
/// </summary>
public static string MsgReady {
get {
return ResourceManager.GetString("MsgReady", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to unable to interpret image format.
/// </summary>
public static string MsgUnableInterpret {
get {
return ResourceManager.GetString("MsgUnableInterpret", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to file could not be opened as resource archive.
/// </summary>
public static string MsgUnknownFormat {
get {
return ResourceManager.GetString("MsgUnknownFormat", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Version {0}.
/// </summary>
public static string MsgVersion {
get {
return ResourceManager.GetString("MsgVersion", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to [builtin].
/// </summary>
public static string TextAboutBuiltin {
get {
return ResourceManager.GetString("TextAboutBuiltin", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Supported archives:.
/// </summary>
public static string TextAboutSupportedArchives {
get {
return ResourceManager.GetString("TextAboutSupportedArchives", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Supported image formats:.
/// </summary>
public static string TextAboutSupportedImages {
get {
return ResourceManager.GetString("TextAboutSupportedImages", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to About Game Resource browser.
/// </summary>
public static string TextAboutTitle {
get {
return ResourceManager.GetString("TextAboutTitle", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to as is.
/// </summary>
public static string TextAsIs {
get {
return ResourceManager.GetString("TextAsIs", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Choose destination directory.
/// </summary>
public static string TextChooseDestDir {
get {
return ResourceManager.GetString("TextChooseDestDir", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to &lt;DIR&gt;.
/// </summary>
public static string TextDirType {
get {
return ResourceManager.GetString("TextDirType", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Text encoding.
/// </summary>
public static string TextEncoding {
get {
return ResourceManager.GetString("TextEncoding", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Extract all files from {0} to.
/// </summary>
public static string TextExtractAllTo {
get {
return ResourceManager.GetString("TextExtractAllTo", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Extract {0} to.
/// </summary>
public static string TextExtractFileTo {
get {
return ResourceManager.GetString("TextExtractFileTo", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Extract images.
/// </summary>
public static string TextExtractImages {
get {
return ResourceManager.GetString("TextExtractImages", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Extract text.
/// </summary>
public static string TextExtractText {
get {
return ResourceManager.GetString("TextExtractText", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Extract from archive.
/// </summary>
public static string TextExtractTitle {
get {
return ResourceManager.GetString("TextExtractTitle", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Archive parameters.
/// </summary>
public static string TextParametersTitle {
get {
return ResourceManager.GetString("TextParametersTitle", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Save as.
/// </summary>
public static string TextSaveAs {
get {
return ResourceManager.GetString("TextSaveAs", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Save images as.
/// </summary>
public static string TextSaveImagesAs {
get {
return ResourceManager.GetString("TextSaveImagesAs", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Game Resource browser.
/// </summary>
public static string TextTitle {
get {
return ResourceManager.GetString("TextTitle", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Back.
/// </summary>
public static string TooltipBack {
get {
return ResourceManager.GetString("TooltipBack", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Forward.
/// </summary>
public static string TooltipForward {
get {
return ResourceManager.GetString("TooltipForward", resourceCulture);
}
}
}
}

297
Strings/guiStrings.resx Normal file
View File

@ -0,0 +1,297 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="ButtonCancel" xml:space="preserve">
<value>Cancel</value>
</data>
<data name="ButtonExtract" xml:space="preserve">
<value>Extract</value>
</data>
<data name="ButtonOK" xml:space="preserve">
<value>OK</value>
</data>
<data name="CtxMenuClose" xml:space="preserve">
<value>_Close</value>
</data>
<data name="CtxMenuCopy" xml:space="preserve">
<value>Copy</value>
</data>
<data name="CtxMenuCut" xml:space="preserve">
<value>Cut</value>
</data>
<data name="CtxMenuDelete" xml:space="preserve">
<value>_Delete</value>
</data>
<data name="CtxMenuExplorer" xml:space="preserve">
<value>Browse in _Explorer</value>
</data>
<data name="CtxMenuExtract" xml:space="preserve">
<value>Extract</value>
</data>
<data name="CtxMenuOpen" xml:space="preserve">
<value>Open</value>
</data>
<data name="CtxMenuPaste" xml:space="preserve">
<value>Paste</value>
</data>
<data name="CtxMenuRefresh" xml:space="preserve">
<value>Refresh</value>
</data>
<data name="CtxMenuRename" xml:space="preserve">
<value>_Rename</value>
</data>
<data name="CtxMenuSortBy" xml:space="preserve">
<value>Sort by</value>
</data>
<data name="CtxMenuSortByName" xml:space="preserve">
<value>Name</value>
</data>
<data name="CtxMenuSortBySize" xml:space="preserve">
<value>Size</value>
</data>
<data name="CtxMenuSortByType" xml:space="preserve">
<value>Type</value>
</data>
<data name="CtxMenuUnsorted" xml:space="preserve">
<value>Unsorted</value>
</data>
<data name="HeaderName" xml:space="preserve">
<value>Name</value>
</data>
<data name="HeaderSize" xml:space="preserve">
<value>Size</value>
</data>
<data name="HeaderType" xml:space="preserve">
<value>Type</value>
</data>
<data name="LPfile1" xml:space="preserve">
<value>file</value>
</data>
<data name="LPfile2" xml:space="preserve">
<value>files</value>
</data>
<data name="MenuAbout" xml:space="preserve">
<value>About</value>
</data>
<data name="MsgDeletedItem" xml:space="preserve">
<value>Deleted {0}</value>
</data>
<data name="MsgDirectoryNotFound" xml:space="preserve">
<value>directory not found</value>
</data>
<data name="MsgEmptyArchive" xml:space="preserve">
<value>archive is empty</value>
</data>
<data name="MsgErrorExtracting" xml:space="preserve">
<value>Error extracting file</value>
</data>
<data name="MsgErrorOpening" xml:space="preserve">
<value>Error opening file</value>
</data>
<data name="MsgExtractComplete" xml:space="preserve">
<value>Extracted {0} into {1}</value>
</data>
<data name="MsgExtractCompletePlural" xml:space="preserve">
<value>Extracted {0} {1}</value>
</data>
<data name="MsgExtractingArchive" xml:space="preserve">
<value>Extracting files from {0}</value>
</data>
<data name="MsgExtractingFile" xml:space="preserve">
<value>Extracting file from {0}</value>
</data>
<data name="MsgExtractingTo" xml:space="preserve">
<value>Extracting files from {0} to {1}</value>
</data>
<data name="MsgImageSize" xml:space="preserve">
<value>Image {0} x {1} pixels</value>
</data>
<data name="MsgNoFiles" xml:space="preserve">
<value>no files to extract</value>
</data>
<data name="MsgReady" xml:space="preserve">
<value>Ready</value>
</data>
<data name="MsgUnableInterpret" xml:space="preserve">
<value>unable to interpret image format</value>
</data>
<data name="MsgUnknownFormat" xml:space="preserve">
<value>file could not be opened as resource archive</value>
</data>
<data name="MsgVersion" xml:space="preserve">
<value>Version {0}</value>
</data>
<data name="TextAboutBuiltin" xml:space="preserve">
<value>[builtin]</value>
</data>
<data name="TextAboutSupportedArchives" xml:space="preserve">
<value>Supported archives:</value>
</data>
<data name="TextAboutSupportedImages" xml:space="preserve">
<value>Supported image formats:</value>
</data>
<data name="TextAboutTitle" xml:space="preserve">
<value>About Game Resource browser</value>
</data>
<data name="TextAsIs" xml:space="preserve">
<value>as is</value>
</data>
<data name="TextChooseDestDir" xml:space="preserve">
<value>Choose destination directory</value>
</data>
<data name="TextDirType" xml:space="preserve">
<value>&lt;DIR&gt;</value>
</data>
<data name="TextEncoding" xml:space="preserve">
<value>Text encoding</value>
</data>
<data name="TextExtractAllTo" xml:space="preserve">
<value>Extract all files from {0} to</value>
</data>
<data name="TextExtractFileTo" xml:space="preserve">
<value>Extract {0} to</value>
</data>
<data name="TextExtractImages" xml:space="preserve">
<value>Extract images</value>
</data>
<data name="TextExtractText" xml:space="preserve">
<value>Extract text</value>
</data>
<data name="TextExtractTitle" xml:space="preserve">
<value>Extract from archive</value>
</data>
<data name="TextParametersTitle" xml:space="preserve">
<value>Archive parameters</value>
</data>
<data name="TextSaveAs" xml:space="preserve">
<value>Save as</value>
</data>
<data name="TextSaveImagesAs" xml:space="preserve">
<value>Save images as</value>
</data>
<data name="TextTitle" xml:space="preserve">
<value>Game Resource browser</value>
</data>
<data name="TooltipBack" xml:space="preserve">
<value>Back</value>
</data>
<data name="TooltipForward" xml:space="preserve">
<value>Forward</value>
</data>
</root>

View File

@ -0,0 +1,300 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="ButtonCancel" xml:space="preserve">
<value>Отмена</value>
</data>
<data name="ButtonExtract" xml:space="preserve">
<value>Извлечь</value>
</data>
<data name="CtxMenuClose" xml:space="preserve">
<value>_Закрыть</value>
</data>
<data name="CtxMenuCopy" xml:space="preserve">
<value>Копировать</value>
</data>
<data name="CtxMenuCut" xml:space="preserve">
<value>Вырезать</value>
</data>
<data name="CtxMenuDelete" xml:space="preserve">
<value>Удалить</value>
</data>
<data name="CtxMenuExplorer" xml:space="preserve">
<value>Просмотр в Explorer</value>
</data>
<data name="CtxMenuExtract" xml:space="preserve">
<value>Извлечь</value>
</data>
<data name="CtxMenuOpen" xml:space="preserve">
<value>Открыть</value>
</data>
<data name="CtxMenuPaste" xml:space="preserve">
<value>Вставить</value>
</data>
<data name="CtxMenuRefresh" xml:space="preserve">
<value>Обновить</value>
</data>
<data name="CtxMenuRename" xml:space="preserve">
<value>Переименовать</value>
</data>
<data name="CtxMenuSortBy" xml:space="preserve">
<value>Сортировка</value>
</data>
<data name="CtxMenuSortByName" xml:space="preserve">
<value>по имени</value>
</data>
<data name="CtxMenuSortBySize" xml:space="preserve">
<value>по размеру</value>
</data>
<data name="CtxMenuSortByType" xml:space="preserve">
<value>по типу</value>
</data>
<data name="CtxMenuUnsorted" xml:space="preserve">
<value>не сортировать</value>
</data>
<data name="HeaderName" xml:space="preserve">
<value>Имя</value>
</data>
<data name="HeaderSize" xml:space="preserve">
<value>Размер</value>
</data>
<data name="HeaderType" xml:space="preserve">
<value>Тип</value>
</data>
<data name="LPfile1" xml:space="preserve">
<value>файл</value>
</data>
<data name="LPfile2" xml:space="preserve">
<value>файла</value>
</data>
<data name="LPfile3" xml:space="preserve">
<value>файлов</value>
</data>
<data name="MenuAbout" xml:space="preserve">
<value>О программе</value>
</data>
<data name="MsgDeletedItem" xml:space="preserve">
<value>Удалён файл {0}</value>
</data>
<data name="MsgDirectoryNotFound" xml:space="preserve">
<value>каталог не найден</value>
</data>
<data name="MsgEmptyArchive" xml:space="preserve">
<value>архив пуст</value>
</data>
<data name="MsgErrorExtracting" xml:space="preserve">
<value>Ошибка извлечения файла</value>
</data>
<data name="MsgErrorOpening" xml:space="preserve">
<value>Ошибка открытия файла</value>
</data>
<data name="MsgExtractComplete" xml:space="preserve">
<value>{0} извлечён в {1}</value>
</data>
<data name="MsgExtractCompletePlural" xml:space="preserve">
<value>Извлечено {0} {1}</value>
</data>
<data name="MsgExtractingArchive" xml:space="preserve">
<value>Извлекаются файлы из {0}</value>
</data>
<data name="MsgExtractingFile" xml:space="preserve">
<value>Файл извлекается из {0}</value>
</data>
<data name="MsgExtractingTo" xml:space="preserve">
<value>Извлекаются файлы из {0} в {1}</value>
</data>
<data name="MsgImageSize" xml:space="preserve">
<value>Изображение {0} x {1} пикселей</value>
</data>
<data name="MsgNoFiles" xml:space="preserve">
<value>отсутствуют файлы, удовлетворяющие выбранным критериям</value>
</data>
<data name="MsgReady" xml:space="preserve">
<value>Готов</value>
</data>
<data name="MsgUnableInterpret" xml:space="preserve">
<value>не удалось интерпретировать формат изображения</value>
</data>
<data name="MsgUnknownFormat" xml:space="preserve">
<value>файл не может быть открыт как архив ресурсов</value>
</data>
<data name="MsgVersion" xml:space="preserve">
<value>Версия {0}</value>
</data>
<data name="TextAboutBuiltin" xml:space="preserve">
<value>[встроен]</value>
</data>
<data name="TextAboutSupportedArchives" xml:space="preserve">
<value>Поддерживаемые архивы:</value>
</data>
<data name="TextAboutSupportedImages" xml:space="preserve">
<value>Поддерживаемые форматы изображений:</value>
</data>
<data name="TextAboutTitle" xml:space="preserve">
<value>Об обозревателе игровых ресурсов</value>
</data>
<data name="TextAsIs" xml:space="preserve">
<value>исходном</value>
</data>
<data name="TextChooseDestDir" xml:space="preserve">
<value>Выберите место извлечения</value>
</data>
<data name="TextDirType" xml:space="preserve">
<value>&lt;DIR&gt;</value>
</data>
<data name="TextEncoding" xml:space="preserve">
<value>Кодировка текста</value>
</data>
<data name="TextExtractAllTo" xml:space="preserve">
<value>Извлечь все файлы из {0} в</value>
</data>
<data name="TextExtractFileTo" xml:space="preserve">
<value>Извлечь {0} в</value>
</data>
<data name="TextExtractImages" xml:space="preserve">
<value>Извлекать изображения</value>
</data>
<data name="TextExtractText" xml:space="preserve">
<value>Извлекать текст</value>
</data>
<data name="TextExtractTitle" xml:space="preserve">
<value>Извлечь из архива</value>
</data>
<data name="TextOK" xml:space="preserve">
<value>OK</value>
</data>
<data name="TextParametersTitle" xml:space="preserve">
<value>Параметры архива</value>
</data>
<data name="TextSaveAs" xml:space="preserve">
<value>Сохранить в формате</value>
</data>
<data name="TextSaveImagesAs" xml:space="preserve">
<value>Сохранить в формате</value>
</data>
<data name="TextTitle" xml:space="preserve">
<value>Обозреватель игровых ресурсов</value>
</data>
<data name="TooltipBack" xml:space="preserve">
<value>Назад</value>
</data>
<data name="TooltipForward" xml:space="preserve">
<value>Вперёд</value>
</data>
</root>

117
Utility.cs Normal file
View File

@ -0,0 +1,117 @@
//! \file Utility.cs
//! \date Sun Jul 06 07:40:34 2014
//! \brief utility classes.
//
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Windows.Input;
using GARbro.GUI.Strings;
namespace GARbro.GUI
{
internal class NativeMethods
{
[DllImport ("shlwapi.dll", CharSet = CharSet.Unicode)]
internal static extern int StrCmpLogicalW (string psz1, string psz2);
[DllImport ("gdi32.dll")]
internal static extern int GetDeviceCaps (IntPtr hDc, int nIndex);
[DllImport ("user32.dll")]
internal static extern IntPtr GetDC (IntPtr hWnd);
[DllImport ("user32.dll")]
internal static extern int ReleaseDC (IntPtr hWnd, IntPtr hDc);
}
public static class Desktop
{
public static int DpiX { get { return dpi_x; } }
public static int DpiY { get { return dpi_y; } }
public const int LOGPIXELSX = 88;
public const int LOGPIXELSY = 90;
private static int dpi_x = GetCaps (LOGPIXELSX);
private static int dpi_y = GetCaps (LOGPIXELSY);
public static int GetCaps (int cap)
{
IntPtr hdc = NativeMethods.GetDC (IntPtr.Zero);
if (hdc == IntPtr.Zero)
return 96;
int dpi = NativeMethods.GetDeviceCaps (hdc, cap);
NativeMethods.ReleaseDC (IntPtr.Zero, hdc);
return dpi;
}
}
public sealed class NumericStringComparer : IComparer<string>
{
public int Compare (string a, string b)
{
return NativeMethods.StrCmpLogicalW (a, b);
}
}
public class WaitCursor : IDisposable
{
private Cursor m_previousCursor;
public WaitCursor()
{
m_previousCursor = Mouse.OverrideCursor;
Mouse.OverrideCursor = Cursors.Wait;
}
#region IDisposable Members
bool disposed = false;
public void Dispose()
{
Dispose (true);
GC.SuppressFinalize (this);
}
protected virtual void Dispose (bool disposing)
{
if (!disposed)
{
Mouse.OverrideCursor = m_previousCursor;
disposed = true;
}
}
#endregion
}
public static class Localization
{
public static string Plural (int n, string en_singular)
{
string suffix;
if (CultureInfo.CurrentUICulture.Name == "ru-RU")
{
suffix = (n%10==1 && n%100!=11 ? "1" : n%10>=2 && n% 10<=4 && (n%100<10 || n%100>=20) ? "2" : "3");
}
else // assume en-EN
{
suffix = 1 == n ? "1" : "2";
}
try
{
var res = guiStrings.ResourceManager.GetString ("LP"+en_singular+suffix);
return res ?? en_singular;
}
catch
{
return en_singular;
}
}
// Localization.Format ("{0:file:files} copied", count);
// public static string Format (string format, params object[] args);
}
}

296
ViewModel.cs Normal file
View File

@ -0,0 +1,296 @@
//! \file ViewModel.cs
//! \date Wed Jul 02 07:29:11 2014
//! \brief GARbro directory list.
//
using System;
using System.IO;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Text.RegularExpressions;
using System.Globalization;
using GameRes;
using GARbro.GUI.Strings;
namespace GARbro.GUI
{
public class SubDirEntry : GameRes.Entry
{
public override string Type { get { return guiStrings.TextDirType; } }
public SubDirEntry (string name)
{
Name = name;
Size = 0;
}
}
public class DirectoryViewModel : ObservableCollection<EntryViewModel>
{
public string Path { get; private set; }
public ICollection<Entry> Source { get; private set; }
public virtual bool IsArchive { get { return false; } }
public DirectoryViewModel (string path, ICollection<Entry> filelist)
{
Path = path;
Source = filelist;
ImportFromSource();
}
protected virtual void ImportFromSource ()
{
if (!string.IsNullOrEmpty (Path) && null != Directory.GetParent (Path))
{
Add (new EntryViewModel (new SubDirEntry (".."), -2));
}
foreach (var entry in Source)
{
int prio = null == entry as SubDirEntry ? 0 : -1;
Add (new EntryViewModel (entry, prio));
}
}
public EntryViewModel Find (string name)
{
return this.FirstOrDefault (e => e.Name.Equals (name, System.StringComparison.OrdinalIgnoreCase));
}
public virtual void SetPosition (DirectoryPosition pos)
{
}
}
public class ArchiveViewModel : DirectoryViewModel
{
public override bool IsArchive { get { return true; } }
public string SubDir { get; protected set; }
public ArchiveViewModel (string path, ArcFile arc)
: base (path, arc.Dir)
{
}
protected override void ImportFromSource ()
{
UpdateModel ("");
}
private string m_delimiter = "/";
private static readonly char[] m_path_delimiters = { '/', '\\' };
public void ChDir (string subdir)
{
string new_path;
if (".." == subdir)
{
if (0 == SubDir.Length)
return;
var path = SubDir.Split (m_path_delimiters);
if (path.Length > 1)
new_path = string.Join (m_delimiter, path, 0, path.Length-1);
else
new_path = "";
}
else
{
var entry = this.FirstOrDefault (e => e.Name.Equals (subdir, StringComparison.OrdinalIgnoreCase));
if (null == entry)
throw new DirectoryNotFoundException (string.Format ("{1}: {0}", guiStrings.MsgDirectoryNotFound, subdir));
if (SubDir.Length > 0)
new_path = SubDir + m_delimiter + entry.Name;
else
new_path = entry.Name;
}
UpdateModel (new_path);
}
static readonly Regex path_re = new Regex (@"\G[/\\]?([^/\\]+)([/\\])");
private void UpdateModel (string root_path)
{
IEnumerable<Entry> dir = Source;
if (!string.IsNullOrEmpty (root_path))
dir = from entry in dir
where entry.Name.StartsWith (root_path+m_delimiter)
select entry;
if (!dir.Any())
{
throw new DirectoryNotFoundException (string.Format ("{1}: {0}", guiStrings.MsgDirectoryNotFound, root_path));
}
m_suppress_notification = true;
try
{
this.Clear();
SubDir = root_path;
Add (new EntryViewModel (new SubDirEntry (".."), -2));
var subdirs = new HashSet<string>();
foreach (var entry in dir)
{
var match = path_re.Match (entry.Name, root_path.Length);
if (match.Success)
{
string name = match.Groups[1].Value;
if (subdirs.Add (name))
{
m_delimiter = match.Groups[2].Value;
Add (new EntryViewModel (new SubDirEntry (name), -1));
}
}
else
{
Add (new EntryViewModel (entry, 0));
}
}
}
finally
{
m_suppress_notification = false;
OnCollectionChanged (new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
}
public override void SetPosition (DirectoryPosition pos)
{
UpdateModel (pos.ArchivePath);
}
public IEnumerable<Entry> GetFiles (EntryViewModel entry)
{
if (!entry.IsDirectory)
return new Entry[] { entry.Source };
string path = GetPath (entry.Name);
return from file in Source
where file.Name.StartsWith (path)
select file;
}
string GetPath (string dir)
{
if (SubDir.Length > 0)
return SubDir + m_delimiter + dir + m_delimiter;
else
return dir + m_delimiter;
}
private bool m_suppress_notification = false;
protected override void OnCollectionChanged (NotifyCollectionChangedEventArgs e)
{
if (!m_suppress_notification)
base.OnCollectionChanged(e);
}
}
public class EntryViewModel
{
public EntryViewModel (Entry entry, int priority)
{
Source = entry;
Name = Path.GetFileName (entry.Name);
Priority = priority;
}
public Entry Source { get; private set; }
public string Name { get; private set; }
public string Type { get { return Source.Type; } }
public uint Size { get { return Source.Size; } }
public int Priority { get; private set; }
public bool IsDirectory { get { return Priority < 0; } }
}
public sealed class FileSystemComparer : IComparer
{
private string m_property;
private int m_direction;
private static Comparer s_default_comparer = new Comparer (CultureInfo.CurrentUICulture);
public FileSystemComparer (string property, ListSortDirection direction)
{
m_property = property;
m_direction = direction == ListSortDirection.Ascending ? 1 : -1;
}
public int Compare (object a, object b)
{
var v_a = a as EntryViewModel;
var v_b = b as EntryViewModel;
if (null == v_a || null == v_b)
return s_default_comparer.Compare (a, b) * m_direction;
if (v_a.Priority < v_b.Priority)
return -1;
if (v_a.Priority > v_b.Priority)
return 1;
if (string.IsNullOrEmpty (m_property))
return 0;
int order;
if (m_property != "Name")
{
if ("Type" == m_property)
{
// empty strings placed in the end
if (string.IsNullOrEmpty (v_a.Type))
order = string.IsNullOrEmpty (v_b.Type) ? 0 : m_direction;
else if (string.IsNullOrEmpty (v_b.Type))
order = -m_direction;
else
order = string.Compare (v_a.Type, v_b.Type, true) * m_direction;
}
else
{
var prop_a = a.GetType ().GetProperty (m_property).GetValue (a);
var prop_b = b.GetType ().GetProperty (m_property).GetValue (b);
order = s_default_comparer.Compare (prop_a, prop_b) * m_direction;
}
if (0 == order)
order = NativeMethods.StrCmpLogicalW (v_a.Name, v_b.Name);
}
else
order = NativeMethods.StrCmpLogicalW (v_a.Name, v_b.Name) * m_direction;
return order;
}
}
/// <summary>
/// Image format model for formats drop-down list widgets.
/// </summary>
public class ImageFormatModel
{
public ImageFormat Source { get; private set; }
public string Tag {
get { return null != Source ? Source.Tag : guiStrings.TextAsIs; }
}
public ImageFormatModel (ImageFormat impl = null)
{
Source = impl;
}
}
/// <summary>
/// Stores current position within directory view model.
/// </summary>
public class DirectoryPosition
{
public string Path { get; set; }
public string ArchivePath { get; set; }
public EntryViewModel Item { get; set; }
public DirectoryPosition (DirectoryViewModel vm, EntryViewModel item)
{
Path = vm.Path;
Item = item;
if (vm.IsArchive)
ArchivePath = (vm as ArchiveViewModel).SubDir;
else
ArchivePath = "";
}
}
}

6
packages.config Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Ookii.Dialogs" version="1.0" targetFramework="net45" />
<package id="WindowsAPICodePack-Core" version="1.1" targetFramework="net45" />
<package id="WindowsAPICodePack-Shell" version="1.1" targetFramework="net45" />
</packages>

25
zlib/changes.txt Normal file
View File

@ -0,0 +1,25 @@
v1.3 june 2013
Upgrade zlib to 1.2.8
Make custom build v1.2.8.1 where 1 bugs fixed: Incorrect move method was sent to SetFilePointer.
Fix bug where utf8 flag was not set correctly.
Change UTF8Encoding to default true.
Support unicode in filename of zip itself.
v1.2 6.may 2012
-Upgrade zlib to 1.2.7
-Change Zip64 option to enum (Yes,No,Auto) where Auto now is default (was No)
v1.1 6.jan 2011
Fixed bug: If Unzipper.ItemList had more than one entry, unzip would not work (exctracted files would try to overwrite themself)
Update zlib dlls to custom build v1.2.5.1 where 2 bugs fixed:
-Adding over 64k number of entries in zip with total size below 4GB created invalid zip
-Writing entries over 4GB with zip64=false did not fail but created invalid zip
Misc:
Convert unsafe code to safe code.
Wrap CloseCurrentEntry in try/finally block: we must always CloseFile, even if CloseCurrentEntry fails.
Zip64 zipping works now.
v1.0
Initial release

BIN
zlib/zlib32.dll Normal file

Binary file not shown.

BIN
zlib/zlib64.dll Normal file

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More