(Kirikiri): Add Kirikiri Z archive creating support.

This commit is contained in:
Crsky 2024-05-26 15:30:45 +08:00
parent 7f74a030a2
commit 8fcb85334e
3 changed files with 67 additions and 7 deletions

View File

@ -479,7 +479,7 @@ NextEntry:
using (var writer = new BinaryWriter (output, Encoding.ASCII, true))
{
writer.Write (s_xp3_header);
if (2 == xp3_options.Version)
if (2 == xp3_options.Version || 3 == xp3_options.Version)
{
writer.Write ((long)0x17);
writer.Write ((int)1);
@ -516,7 +516,7 @@ NextEntry:
&& !(scheme.StartupTjsNotEncrypted && VFS.IsPathEqualsToFileName (name, "startup.tjs"))
};
bool compress = compress_contents && ShouldCompressFile (entry);
using (var file = File.Open (name, FileMode.Open, FileAccess.Read))
using (var file = File.Open (name, FileMode.Open, FileAccess.Read, FileShare.Read))
{
if (!xp3entry.IsEncrypted || 0 == file.Length)
RawFileCopy (file, xp3entry, output, compress);
@ -538,20 +538,46 @@ NextEntry:
callback (callback_count++, null, arcStrings.MsgWritingIndex);
long dir_pos = 0;
if (3 == xp3_options.Version)
{
foreach (var entry in dir)
{
header.Write ((uint)0x6e666e68); // "hnfn"
header.Write ((long)(4+2+entry.Name.Length*2));
header.Write ((uint)entry.Hash);
header.Write ((short)entry.Name.Length);
foreach (char c in entry.Name)
header.Write (c);
}
dir_pos = header.BaseStream.Position;
}
foreach (var entry in dir)
{
var entry_name = entry.Name;
if (3 == xp3_options.Version)
{
using (var md5 = MD5.Create())
{
var text_bytes = Encoding.Unicode.GetBytes(entry.Name.ToLowerInvariant());
var hash = md5.ComputeHash(text_bytes);
var sb = new StringBuilder(32);
for (int i = 0; i < hash.Length; ++i)
sb.AppendFormat("{0:x2}", hash[i]);
entry_name = sb.ToString();
}
}
header.BaseStream.Position = dir_pos;
header.Write ((uint)0x656c6946); // "File"
long header_size_pos = header.BaseStream.Position;
header.Write ((long)0);
header.Write ((uint)0x6f666e69); // "info"
header.Write ((long)(4+8+8+2 + entry.Name.Length*2));
header.Write ((long)(4+8+8+2 + entry_name.Length*2));
header.Write ((uint)(use_encryption ? 0x80000000 : 0));
header.Write ((long)entry.UnpackedSize);
header.Write ((long)entry.Size);
header.Write ((short)entry.Name.Length);
foreach (char c in entry.Name)
header.Write ((short)entry_name.Length);
foreach (char c in entry_name)
header.Write (c);
header.Write ((uint)0x6d676573); // "segm"

View File

@ -4,6 +4,9 @@
xmlns:s="clr-namespace:GameRes.Formats.Strings"
xmlns:p="clr-namespace:GameRes.Formats.Properties"
xmlns:local="clr-namespace:GameRes.Formats.GUI">
<Grid.Resources>
<local:Xp3VersionConverter x:Key="Xp3VersionConverter"></local:Xp3VersionConverter>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
@ -14,9 +17,10 @@
<StackPanel Orientation="Vertical" Margin="0,0,10,5">
<Label Content="{x:Static s:arcStrings.XP3LabelVersion}" Target="{Binding ElementName=Version}" Padding="4,0,0,5"/>
<ComboBox Name="Version" Width="80" HorizontalAlignment="Left" SelectedValuePath="Content"
SelectedValue="{Binding Source={x:Static p:Settings.Default}, Path=XP3Version, Mode=TwoWay}">
SelectedValue="{Binding Source={x:Static p:Settings.Default}, Path=XP3Version, Mode=TwoWay, Converter={StaticResource Xp3VersionConverter}}">
<ComboBoxItem Content="1"/>
<ComboBoxItem Content="2"/>
<ComboBoxItem Content="Z"/>
</ComboBox>
</StackPanel>
<StackPanel Orientation="Vertical" Margin="0,0,0,5">

View File

@ -1,5 +1,8 @@
using System.Windows;
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
namespace GameRes.Formats.GUI
{
@ -13,4 +16,31 @@ namespace GameRes.Formats.GUI
InitializeComponent ();
}
}
public class Xp3VersionConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var val = (int)value;
switch (val)
{
case 1: return "1";
case 2: return "2";
case 3: return "Z";
default: throw new NotImplementedException();
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
var str = value.ToString();
switch (str)
{
case "1": return 1;
case "2": return 2;
case "Z": return 3;
default: throw new NotImplementedException();
}
}
}
}