CTZLauncher/CTZLauncher/Tools/ZipTools.cs

227 lines
6.2 KiB
C#

namespace KMCCC.Tools
{
#region
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.IO.Packaging;
using System.Linq;
using System.Reflection;
using System.Text;
#endregion
/// <summary>
/// 操蛋的通过反射调用Zip解压
/// </summary>
public static class ZipTools
{
public static readonly Boolean Enabled;
public static readonly Type ZipArchive;
public static readonly MethodInfo ZipArchive_OpenOnFile;
public static readonly MethodInfo ZipArchive_GetFiles;
public static readonly FieldInfo ZipArchive_ZipIOBlockManager;
public static readonly Type ZipFileInfo;
public static readonly MethodInfo ZipFileInfo_GetStream;
public static readonly PropertyInfo ZipFileInfo_Name;
public static readonly PropertyInfo ZipFileInfo_FolderFlag;
public static readonly Type ZipIOBlockManager;
public static readonly FieldInfo ZipIOBlockManager_Encoding;
static ZipTools()
{
try
{
var windowsBase = typeof (Package).Assembly;
ZipArchive = windowsBase.GetType("MS.Internal.IO.Zip.ZipArchive");
ZipArchive_OpenOnFile = ZipArchive.GetMethod("OpenOnFile", BindingFlags.NonPublic | BindingFlags.Static);
ZipArchive_GetFiles = ZipArchive.GetMethod("GetFiles", BindingFlags.NonPublic | BindingFlags.Instance);
ZipArchive_ZipIOBlockManager = ZipArchive.GetField("_blockManager", BindingFlags.NonPublic | BindingFlags.Instance);
ZipFileInfo = windowsBase.GetType("MS.Internal.IO.Zip.ZipFileInfo");
ZipFileInfo_GetStream = ZipFileInfo.GetMethod("GetStream", BindingFlags.NonPublic | BindingFlags.Instance);
ZipFileInfo_Name = ZipFileInfo.GetProperty("Name", BindingFlags.NonPublic | BindingFlags.Instance);
ZipFileInfo_FolderFlag = ZipFileInfo.GetProperty("FolderFlag", BindingFlags.NonPublic | BindingFlags.Instance);
ZipIOBlockManager = windowsBase.GetType("MS.Internal.IO.Zip.ZipIOBlockManager");
ZipIOBlockManager_Encoding = ZipIOBlockManager.GetField("_encoding", BindingFlags.NonPublic | BindingFlags.Instance);
Enabled = true;
}
catch
{
Enabled = false;
}
}
public static bool Unzip(string zipFile, string outputDirectory, UnzipOptions options)
{
return UnzipFile(zipFile, outputDirectory, options) == null;
}
public static Exception UnzipFile(string zipFile, string outputDirectory, UnzipOptions options)
{
options = options ?? new UnzipOptions();
try
{
var root = new DirectoryInfo(outputDirectory);
root.Create();
var rootPath = root.FullName + "/";
using (var zip = (IDisposable) ZipArchive_OpenOnFile.Invoke(null, new object[] {zipFile, FileMode.Open, FileAccess.Read, FileShare.Read, false}))
{
var ioManager = ZipArchive_ZipIOBlockManager.GetValue(zip);
ZipIOBlockManager_Encoding.SetValue(ioManager, new WarpedEncoding(options.Encoding ?? Encoding.Default));
var files = (IEnumerable) ZipArchive_GetFiles.Invoke(zip, new object[] {});
IEnumerable<string> exclude = (options.Exclude ?? new List<string>());
if (exclude.Count() > 1000)
{
exclude = exclude.AsParallel();
}
foreach (var item in files)
{
var name = (string) ZipFileInfo_Name.GetValue(item, null);
if (exclude.Any(name.StartsWith))
{
continue;
}
if ((bool) ZipFileInfo_FolderFlag.GetValue(item, null))
{
Directory.CreateDirectory(rootPath + name);
continue;
}
using (var stream = (Stream) ZipFileInfo_GetStream.Invoke(item, new object[] {FileMode.Open, FileAccess.Read}))
{
var filePath = rootPath + name;
var directoryInfo = new FileInfo(filePath).Directory;
if (directoryInfo != null) directoryInfo.Create();
using (var fs = new FileStream(filePath, FileMode.Create))
{
stream.CopyTo(fs);
}
}
}
}
return null;
}
catch (Exception exp)
{
return exp;
}
}
#region 编码大法
public class WarpedEncoding : ASCIIEncoding
{
private readonly Encoding _innerEncoding;
public WarpedEncoding(Encoding encoding)
{
_innerEncoding = encoding ?? Default;
}
public override bool Equals(object value)
{
return _innerEncoding.Equals(value);
}
public override int GetByteCount(char[] chars, int index, int count)
{
return _innerEncoding.GetByteCount(chars, index, count);
}
public override int GetByteCount(string chars)
{
return _innerEncoding.GetByteCount(chars);
}
public override int GetBytes(char[] chars, int charIndex, int charCount, byte[] bytes, int byteIndex)
{
return _innerEncoding.GetBytes(chars, charIndex, charCount, bytes, byteIndex);
}
public override int GetBytes(string s, int charIndex, int charCount, byte[] bytes, int byteIndex)
{
return _innerEncoding.GetBytes(s, charIndex, charCount, bytes, byteIndex);
}
public override int GetCharCount(byte[] bytes, int index, int count)
{
return _innerEncoding.GetCharCount(bytes, index, count);
}
public override int GetChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex)
{
return _innerEncoding.GetChars(bytes, byteIndex, byteCount, chars, charIndex);
}
public override Decoder GetDecoder()
{
return _innerEncoding.GetDecoder();
}
public override Encoder GetEncoder()
{
return _innerEncoding.GetEncoder();
}
public override int GetHashCode()
{
return _innerEncoding.GetHashCode();
}
public override int GetMaxByteCount(int charCount)
{
return _innerEncoding.GetMaxByteCount(charCount);
}
public override int GetMaxCharCount(int byteCount)
{
return _innerEncoding.GetMaxCharCount(byteCount);
}
public override byte[] GetPreamble()
{
return _innerEncoding.GetPreamble();
}
public override string GetString(byte[] bytes, int index, int count)
{
return _innerEncoding.GetString(bytes, index, count);
}
}
#endregion
}
/// <summary>
/// 解压选项
/// </summary>
public class UnzipOptions
{
/// <summary>
/// 排除的文件(夹)
/// </summary>
public List<string> Exclude { get; set; }
/// <summary>
/// 文件(夹)名使用的编码
/// </summary>
public Encoding Encoding { get; set; }
}
}