mirror of
https://github.com/crskycode/GARbro.git
synced 2024-12-24 03:44:13 +08:00
implemented Kogado archives creation.
This commit is contained in:
parent
906d168379
commit
f06396f1e3
@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel.Composition;
|
using System.ComponentModel.Composition;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
@ -50,11 +51,16 @@ namespace GameRes.Formats.Kogado
|
|||||||
[Export(typeof(ArchiveFormat))]
|
[Export(typeof(ArchiveFormat))]
|
||||||
public class PakOpener : ArchiveFormat
|
public class PakOpener : ArchiveFormat
|
||||||
{
|
{
|
||||||
public override string Tag { get { return "PAK"; } }
|
public override string Tag { get { return "KOGADO"; } }
|
||||||
public override string Description { get { return arcStrings.KogadoDescription; } }
|
public override string Description { get { return arcStrings.KogadoDescription; } }
|
||||||
public override uint Signature { get { return 0x61507948; } } // 'HyPa'
|
public override uint Signature { get { return 0x61507948; } } // 'HyPa'
|
||||||
public override bool IsHierarchic { get { return false; } }
|
public override bool IsHierarchic { get { return false; } }
|
||||||
public override bool CanCreate { get { return false; } }
|
public override bool CanCreate { get { return true; } }
|
||||||
|
|
||||||
|
public PakOpener ()
|
||||||
|
{
|
||||||
|
Extensions = new string[] { "pak" };
|
||||||
|
}
|
||||||
|
|
||||||
public override ArcFile TryOpen (ArcView file)
|
public override ArcFile TryOpen (ArcView file)
|
||||||
{
|
{
|
||||||
@ -143,11 +149,123 @@ namespace GameRes.Formats.Kogado
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal class OutputEntry : KogadoEntry
|
||||||
|
{
|
||||||
|
public byte[] IndexName;
|
||||||
|
public byte[] IndexExt;
|
||||||
|
}
|
||||||
|
|
||||||
// files inside archive are aligned to 0x10 boundary.
|
// files inside archive are aligned to 0x10 boundary.
|
||||||
// to convert DateTime structure into entry time:
|
// to convert DateTime structure into entry time:
|
||||||
// entry.FileTime = file_info.CreationTimeUtc.Ticks;
|
// entry.FileTime = file_info.CreationTimeUtc.Ticks;
|
||||||
//
|
//
|
||||||
// last two bytes of archive is CRC16 of the whole file
|
// last two bytes of archive is CRC16 of the whole file
|
||||||
|
|
||||||
|
public override void Create (Stream output, IEnumerable<Entry> list, ResourceOptions options,
|
||||||
|
EntryCallback callback)
|
||||||
|
{
|
||||||
|
const long data_offset = 0x10;
|
||||||
|
var encoding = Encodings.cp932.WithFatalFallback();
|
||||||
|
int callback_count = 0;
|
||||||
|
|
||||||
|
var output_list = new List<OutputEntry> (list.Count());
|
||||||
|
foreach (var entry in list)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string name = Path.GetFileNameWithoutExtension (entry.Name);
|
||||||
|
string ext = Path.GetExtension (entry.Name).TrimStart ('.').ToLowerInvariant();
|
||||||
|
byte[] name_buf = new byte[0x15];
|
||||||
|
byte[] ext_buf = new byte[3];
|
||||||
|
encoding.GetBytes (name, 0, name.Length, name_buf, 0);
|
||||||
|
if (!string.IsNullOrEmpty (ext))
|
||||||
|
encoding.GetBytes (ext, 0, ext.Length, ext_buf, 0);
|
||||||
|
var out_entry = new OutputEntry
|
||||||
|
{
|
||||||
|
Name = entry.Name,
|
||||||
|
IndexName = name_buf,
|
||||||
|
IndexExt = ext_buf,
|
||||||
|
};
|
||||||
|
output_list.Add (out_entry);
|
||||||
|
}
|
||||||
|
catch (EncoderFallbackException X)
|
||||||
|
{
|
||||||
|
throw new InvalidFileName (entry.Name, arcStrings.MsgIllegalCharacters, X);
|
||||||
|
}
|
||||||
|
catch (ArgumentException X)
|
||||||
|
{
|
||||||
|
throw new InvalidFileName (entry.Name, arcStrings.MsgFileNameTooLong, X);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null != callback)
|
||||||
|
callback (output_list.Count+2, null, null);
|
||||||
|
|
||||||
|
output.Position = data_offset;
|
||||||
|
uint current_offset = 0;
|
||||||
|
foreach (var entry in output_list)
|
||||||
|
{
|
||||||
|
if (null != callback)
|
||||||
|
callback (callback_count++, entry, arcStrings.MsgAddingFile);
|
||||||
|
|
||||||
|
entry.FileTime = File.GetCreationTimeUtc (entry.Name).Ticks;
|
||||||
|
entry.Offset = current_offset;
|
||||||
|
entry.CompressionType = 0;
|
||||||
|
using (var input = File.OpenRead (entry.Name))
|
||||||
|
{
|
||||||
|
var size = input.Length;
|
||||||
|
if (size > uint.MaxValue || current_offset + size + 0x0f > uint.MaxValue)
|
||||||
|
throw new FileSizeException();
|
||||||
|
entry.Size = (uint)size;
|
||||||
|
entry.UnpackedSize = entry.Size;
|
||||||
|
using (var checked_stream = new CheckedStream (output, new Crc16()))
|
||||||
|
{
|
||||||
|
input.CopyTo (checked_stream);
|
||||||
|
entry.HasCheckSum = true;
|
||||||
|
entry.CheckSum = (ushort)checked_stream.CheckSumValue;
|
||||||
|
}
|
||||||
|
current_offset += (uint)size + 0x0f;
|
||||||
|
current_offset &= ~0x0fu;
|
||||||
|
output.Position = data_offset + current_offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null != callback)
|
||||||
|
callback (callback_count++, null, arcStrings.MsgUpdatingIndex);
|
||||||
|
|
||||||
|
// at last, go back to directory and write offset/sizes
|
||||||
|
uint index_offset = current_offset;
|
||||||
|
using (var index = new BinaryWriter (output, encoding, true))
|
||||||
|
{
|
||||||
|
foreach (var entry in output_list)
|
||||||
|
{
|
||||||
|
index.Write (entry.IndexName);
|
||||||
|
index.Write (entry.IndexExt);
|
||||||
|
index.Write ((uint)entry.Offset);
|
||||||
|
index.Write (entry.UnpackedSize);
|
||||||
|
index.Write (entry.Size);
|
||||||
|
index.Write (entry.CompressionType);
|
||||||
|
index.Write (entry.HasCheckSum);
|
||||||
|
index.Write (entry.CheckSum);
|
||||||
|
index.Write (entry.FileTime);
|
||||||
|
}
|
||||||
|
index.BaseStream.Position = 0;
|
||||||
|
index.Write (Signature);
|
||||||
|
index.Write (0x03006b63);
|
||||||
|
index.Write (index_offset);
|
||||||
|
index.Write (output_list.Count);
|
||||||
|
|
||||||
|
if (null != callback)
|
||||||
|
callback (callback_count++, null, arcStrings.MsgCalculatingChecksum);
|
||||||
|
|
||||||
|
output.Position = 0;
|
||||||
|
using (var checked_stream = new CheckedStream (output, new Crc16()))
|
||||||
|
{
|
||||||
|
checked_stream.CopyTo (Stream.Null);
|
||||||
|
index.Write ((ushort)checked_stream.CheckSumValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class Crc16 : ICheckSum
|
public sealed class Crc16 : ICheckSum
|
||||||
@ -261,10 +379,12 @@ namespace GameRes.Formats.Kogado
|
|||||||
|
|
||||||
public sealed class NotTransform : ICryptoTransform
|
public sealed class NotTransform : ICryptoTransform
|
||||||
{
|
{
|
||||||
|
private const int BlockSize = 256;
|
||||||
|
|
||||||
public bool CanReuseTransform { get { return true; } }
|
public bool CanReuseTransform { get { return true; } }
|
||||||
public bool CanTransformMultipleBlocks { get { return true; } }
|
public bool CanTransformMultipleBlocks { get { return true; } }
|
||||||
public int InputBlockSize { get { return 256; } }
|
public int InputBlockSize { get { return BlockSize; } }
|
||||||
public int OutputBlockSize { get { return 256; } }
|
public int OutputBlockSize { get { return BlockSize; } }
|
||||||
|
|
||||||
public int TransformBlock (byte[] inputBuffer, int inputOffset, int inputCount,
|
public int TransformBlock (byte[] inputBuffer, int inputOffset, int inputCount,
|
||||||
byte[] outputBuffer, int outputOffset)
|
byte[] outputBuffer, int outputOffset)
|
||||||
|
9
ArcFormats/Strings/arcStrings.Designer.cs
generated
9
ArcFormats/Strings/arcStrings.Designer.cs
generated
@ -243,6 +243,15 @@ namespace GameRes.Formats.Strings {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Calcualting checksum....
|
||||||
|
/// </summary>
|
||||||
|
public static string MsgCalculatingChecksum {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("MsgCalculatingChecksum", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Compressing index....
|
/// Looks up a localized string similar to Compressing index....
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -180,6 +180,9 @@ predefined encryption scheme.</value>
|
|||||||
<data name="MsgAddingFile" xml:space="preserve">
|
<data name="MsgAddingFile" xml:space="preserve">
|
||||||
<value>Adding file</value>
|
<value>Adding file</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="MsgCalculatingChecksum" xml:space="preserve">
|
||||||
|
<value>Calcualting checksum...</value>
|
||||||
|
</data>
|
||||||
<data name="MsgCompressingIndex" xml:space="preserve">
|
<data name="MsgCompressingIndex" xml:space="preserve">
|
||||||
<value>Compressing index...</value>
|
<value>Compressing index...</value>
|
||||||
</data>
|
</data>
|
||||||
|
@ -162,6 +162,9 @@
|
|||||||
<data name="MsgAddingFile" xml:space="preserve">
|
<data name="MsgAddingFile" xml:space="preserve">
|
||||||
<value>Добавляется файл</value>
|
<value>Добавляется файл</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="MsgCalculatingChecksum" xml:space="preserve">
|
||||||
|
<value>Подсчёт контрольной суммы...</value>
|
||||||
|
</data>
|
||||||
<data name="MsgCompressingIndex" xml:space="preserve">
|
<data name="MsgCompressingIndex" xml:space="preserve">
|
||||||
<value>Сжимается оглавление...</value>
|
<value>Сжимается оглавление...</value>
|
||||||
</data>
|
</data>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user