(ZipOpener.SearchForSignature): added signature sequence as a parameter.

This commit is contained in:
morkt 2018-01-22 15:50:29 +04:00
parent d4fd642cc7
commit eaa3ce4702

View File

@ -89,25 +89,16 @@ namespace GameRes.Formats.PkWare
public override bool IsHierarchic { get { return true; } } public override bool IsHierarchic { get { return true; } }
public override bool CanWrite { get { return true; } } public override bool CanWrite { get { return true; } }
static readonly byte[] PkDirSignature = { (byte)'P', (byte)'K', 5, 6 };
public override ArcFile TryOpen (ArcView file) public override ArcFile TryOpen (ArcView file)
{ {
if (-1 == SearchForSignature (file)) if (-1 == SearchForSignature (file, PkDirSignature))
return null; return null;
var input = file.CreateStream(); var input = file.CreateStream();
try try
{ {
var zip = new ZipArchive (input, ZipArchiveMode.Read, false, Encodings.cp932); return OpenZipArchive (file, input);
try
{
var dir = zip.Entries.Where (z => !z.FullName.EndsWith ("/"))
.Select (z => new ZipEntry (z) as Entry).ToList();
return new PkZipArchive (file, this, dir, zip);
}
catch
{
zip.Dispose();
throw;
}
} }
catch catch
{ {
@ -116,6 +107,22 @@ namespace GameRes.Formats.PkWare
} }
} }
internal ArcFile OpenZipArchive (ArcView file, Stream input)
{
var zip = new ZipArchive (input, ZipArchiveMode.Read, false, Encodings.cp932);
try
{
var dir = zip.Entries.Where (z => !z.FullName.EndsWith ("/"))
.Select (z => new ZipEntry (z) as Entry).ToList();
return new PkZipArchive (file, this, dir, zip);
}
catch
{
zip.Dispose();
throw;
}
}
public override Stream OpenEntry (ArcFile arc, Entry entry) public override Stream OpenEntry (ArcFile arc, Entry entry)
{ {
return ((ZipEntry)entry).NativeEntry.Open(); return ((ZipEntry)entry).NativeEntry.Open();
@ -125,26 +132,27 @@ namespace GameRes.Formats.PkWare
/// Search for ZIP 'End of central directory record' near the end of file. /// Search for ZIP 'End of central directory record' near the end of file.
/// Returns offset of 'PK' signature or -1 if no signature was found. /// Returns offset of 'PK' signature or -1 if no signature was found.
/// </summary> /// </summary>
private unsafe long SearchForSignature (ArcView file) internal unsafe long SearchForSignature (ArcView file, byte[] signature)
{ {
if (signature.Length < 4)
throw new ArgumentException ("Invalid ZIP file signature", "signature");
uint tail_size = (uint)Math.Min (file.MaxOffset, 0x10016L); uint tail_size = (uint)Math.Min (file.MaxOffset, 0x10016L);
if (tail_size < 0x16) if (tail_size < 0x16)
return -1; return -1;
var start_offset = file.MaxOffset - tail_size; var start_offset = file.MaxOffset - tail_size;
using (var view = file.CreateViewAccessor (start_offset, tail_size)) using (var view = file.CreateViewAccessor (start_offset, tail_size))
using (var pointer = new ViewPointer (view, start_offset))
{ {
byte* ptr_end = view.GetPointer (start_offset); byte* ptr_end = pointer.Value;
byte* ptr = ptr_end + tail_size-0x16; byte* ptr = ptr_end + tail_size-0x16;
try { for (; ptr >= ptr_end; --ptr)
for (; ptr >= ptr_end; --ptr) {
{ if (signature[3] == ptr[3] && signature[2] == ptr[2] &&
if (6 == ptr[3] && 5 == ptr[2] && 'K' == ptr[1] && 'P' == ptr[0]) signature[1] == ptr[1] && signature[0] == ptr[0])
return start_offset + (ptr-ptr_end); return start_offset + (ptr-ptr_end);
}
return -1;
} finally {
view.SafeMemoryMappedViewHandle.ReleasePointer();
} }
return -1;
} }
} }