/****************************************************************************
* Copyright 2019 Nreal Techonology Limited. All rights reserved.
*
* This file is part of NRSDK.
*
* https://www.nreal.ai/
*
*****************************************************************************/
namespace NRKernal
{
using System.IO;
using UnityEngine;
using ICSharpCode.SharpZipLib.Zip;
using System;
/// A zip utility.
public class ZipUtility
{
#region ZipCallback
/// A zip callback.
public class ZipCallback
{
/// The on pre zip callback.
public Action OnPreZipCallback;
/// The on post zip callback.
public Action OnPostZipCallback;
/// The on finished callback.
public Action OnFinishedCallback;
/// Constructor.
/// The onprezip.
/// The onpostzip.
/// The onfinish.
public ZipCallback(Action onprezip, Action onpostzip, Action onfinish)
{
OnPreZipCallback = onprezip;
OnPostZipCallback = onpostzip;
OnFinishedCallback = onfinish;
}
/// Constructor.
/// The onfinish.
public ZipCallback(Action onfinish) : this(null, null, onfinish)
{
}
/// Executes the 'pre zip' action.
/// The entry.
/// True if it succeeds, false if it fails.
public virtual bool OnPreZip(ZipEntry _entry)
{
if (OnPreZipCallback != null)
{
OnPreZipCallback(_entry);
}
return true;
}
/// Executes the 'post zip' action.
/// The entry.
public virtual void OnPostZip(ZipEntry _entry)
{
if (OnPostZipCallback != null)
{
OnPostZipCallback(_entry);
}
}
/// Executes the 'finished' action.
/// True to result.
public virtual void OnFinished(bool _result)
{
if (OnFinishedCallback != null)
{
OnFinishedCallback(_result);
}
}
}
#endregion
#region UnzipCallback
/// An unzip callback.
public abstract class UnzipCallback
{
/// The on pre zip callback.
public Action OnPreZipCallback;
/// The on post zip callback.
public Action OnPostZipCallback;
/// The on finished callback.
public Action OnFinishedCallback;
/// Constructor.
/// The onprezip.
/// The onpostzip.
/// The onfinish.
public UnzipCallback(Action onprezip, Action onpostzip, Action onfinish)
{
OnPreZipCallback = onprezip;
OnPostZipCallback = onpostzip;
OnFinishedCallback = onfinish;
}
/// Constructor.
/// The onfinish.
public UnzipCallback(Action onfinish) : this(null, null, onfinish)
{
}
/// Executes the 'pre unzip' action.
/// The entry.
/// True if it succeeds, false if it fails.
public virtual bool OnPreUnzip(ZipEntry _entry)
{
if (OnPreZipCallback != null)
{
OnPreZipCallback(_entry);
}
return true;
}
/// Executes the 'post unzip' action.
/// The entry.
public virtual void OnPostUnzip(ZipEntry _entry)
{
if (OnPostZipCallback != null)
{
OnPostZipCallback(_entry);
}
}
/// Executes the 'finished' action.
/// True to result.
public virtual void OnFinished(bool _result)
{
if (OnFinishedCallback != null)
{
OnFinishedCallback(_result);
}
}
}
#endregion
/// Zips.
/// Array of file or directories.
/// Full pathname of the output file.
/// (Optional) The password.
/// (Optional) The zip callback.
/// True if it succeeds, false if it fails.
public static bool Zip(string[] _fileOrDirectoryArray, string _outputPathName, string _password = null, ZipCallback _zipCallback = null)
{
if ((null == _fileOrDirectoryArray) || string.IsNullOrEmpty(_outputPathName))
{
if (null != _zipCallback)
_zipCallback.OnFinished(false);
return false;
}
ZipOutputStream zipOutputStream = new ZipOutputStream(File.Create(_outputPathName));
zipOutputStream.SetLevel(6); // 压缩质量和压缩速度的平衡点
if (!string.IsNullOrEmpty(_password))
zipOutputStream.Password = _password;
for (int index = 0; index < _fileOrDirectoryArray.Length; ++index)
{
bool result = false;
string fileOrDirectory = _fileOrDirectoryArray[index];
if (Directory.Exists(fileOrDirectory))
result = ZipDirectory(fileOrDirectory, string.Empty, zipOutputStream, _zipCallback);
else if (File.Exists(fileOrDirectory))
result = ZipFile(fileOrDirectory, string.Empty, zipOutputStream, _zipCallback);
if (!result)
{
if (null != _zipCallback)
_zipCallback.OnFinished(false);
return false;
}
}
zipOutputStream.Finish();
zipOutputStream.Close();
if (null != _zipCallback)
_zipCallback.OnFinished(true);
return true;
}
/// Unzip file.
/// Full pathname of the file file.
/// Full pathname of the output file.
/// (Optional) The password.
/// (Optional) The unzip callback.
/// True if it succeeds, false if it fails.
public static bool UnzipFile(string _filePathName, string _outputPath, string _password = null, UnzipCallback _unzipCallback = null)
{
if (string.IsNullOrEmpty(_filePathName) || string.IsNullOrEmpty(_outputPath))
{
if (null != _unzipCallback)
_unzipCallback.OnFinished(false);
return false;
}
try
{
return UnzipFile(File.OpenRead(_filePathName), _outputPath, _password, _unzipCallback);
}
catch (System.Exception _e)
{
NRDebugger.Error("[ZipUtility.UnzipFile]: " + _e.ToString());
if (null != _unzipCallback)
_unzipCallback.OnFinished(false);
return false;
}
}
/// Unzip file.
/// The file in bytes.
/// Full pathname of the output file.
/// (Optional) The password.
/// (Optional) The unzip callback.
/// True if it succeeds, false if it fails.
public static bool UnzipFile(byte[] _fileBytes, string _outputPath, string _password = null, UnzipCallback _unzipCallback = null)
{
if ((null == _fileBytes) || string.IsNullOrEmpty(_outputPath))
{
if (null != _unzipCallback)
_unzipCallback.OnFinished(false);
return false;
}
bool result = UnzipFile(new MemoryStream(_fileBytes), _outputPath, _password, _unzipCallback);
if (!result)
{
if (null != _unzipCallback)
_unzipCallback.OnFinished(false);
}
return result;
}
/// Unzip file.
/// Stream to read data from.
/// Full pathname of the output file.
/// (Optional) The password.
/// (Optional) The unzip callback.
/// True if it succeeds, false if it fails.
public static bool UnzipFile(Stream _inputStream, string _outputPath, string _password = null, UnzipCallback _unzipCallback = null)
{
if ((null == _inputStream) || string.IsNullOrEmpty(_outputPath))
{
if (null != _unzipCallback)
_unzipCallback.OnFinished(false);
return false;
}
// 创建文件目录
if (!Directory.Exists(_outputPath))
Directory.CreateDirectory(_outputPath);
// 解压Zip包
ZipEntry entry = null;
using (ZipInputStream zipInputStream = new ZipInputStream(_inputStream))
{
if (!string.IsNullOrEmpty(_password))
zipInputStream.Password = _password;
while (null != (entry = zipInputStream.GetNextEntry()))
{
if (string.IsNullOrEmpty(entry.Name))
continue;
if ((null != _unzipCallback) && !_unzipCallback.OnPreUnzip(entry))
continue; // 过滤
string filePathName = Path.Combine(_outputPath, entry.Name);
// 创建文件目录
if (entry.IsDirectory)
{
Directory.CreateDirectory(filePathName);
continue;
}
// 写入文件
try
{
using (FileStream fileStream = File.Create(filePathName))
{
byte[] bytes = new byte[1024];
while (true)
{
int count = zipInputStream.Read(bytes, 0, bytes.Length);
if (count > 0)
fileStream.Write(bytes, 0, count);
else
{
if (null != _unzipCallback)
_unzipCallback.OnPostUnzip(entry);
break;
}
}
}
}
catch (System.Exception _e)
{
NRDebugger.Error("[ZipUtility.UnzipFile]: " + _e.ToString());
if (null != _unzipCallback)
_unzipCallback.OnFinished(false);
return false;
}
}
}
if (null != _unzipCallback)
_unzipCallback.OnFinished(true);
return true;
}
/// Zip file.
/// Full pathname of the file file.
/// Full pathname of the parent relative file.
/// The zip output stream.
/// (Optional) The zip callback.
/// True if it succeeds, false if it fails.
private static bool ZipFile(string _filePathName, string _parentRelPath, ZipOutputStream _zipOutputStream, ZipCallback _zipCallback = null)
{
//Crc32 crc32 = new Crc32();
ZipEntry entry = null;
FileStream fileStream = null;
try
{
string entryName = _parentRelPath + '/' + Path.GetFileName(_filePathName);
entry = new ZipEntry(entryName);
entry.DateTime = System.DateTime.Now;
if ((null != _zipCallback) && !_zipCallback.OnPreZip(entry))
return true; // 过滤
fileStream = File.OpenRead(_filePathName);
byte[] buffer = new byte[fileStream.Length];
fileStream.Read(buffer, 0, buffer.Length);
fileStream.Close();
entry.Size = buffer.Length;
//crc32.Reset();
//crc32.Update(buffer);
//entry.Crc = crc32.Value;
_zipOutputStream.PutNextEntry(entry);
_zipOutputStream.Write(buffer, 0, buffer.Length);
}
catch (System.Exception _e)
{
NRDebugger.Error("[ZipUtility.ZipFile]: " + _e.ToString());
return false;
}
finally
{
if (null != fileStream)
{
fileStream.Close();
fileStream.Dispose();
}
}
if (null != _zipCallback)
_zipCallback.OnPostZip(entry);
return true;
}
/// Zip directory.
/// Full pathname of the file.
/// Full pathname of the parent relative file.
/// The zip output stream.
/// (Optional) The zip callback.
/// True if it succeeds, false if it fails.
private static bool ZipDirectory(string _path, string _parentRelPath, ZipOutputStream _zipOutputStream, ZipCallback _zipCallback = null)
{
ZipEntry entry = null;
try
{
string entryName = Path.Combine(_parentRelPath, Path.GetFileName(_path) + '/');
entry = new ZipEntry(entryName);
entry.DateTime = System.DateTime.Now;
entry.Size = 0;
if ((null != _zipCallback) && !_zipCallback.OnPreZip(entry))
return true; // 过滤
_zipOutputStream.PutNextEntry(entry);
_zipOutputStream.Flush();
string[] files = Directory.GetFiles(_path);
for (int index = 0; index < files.Length; ++index)
ZipFile(files[index], Path.Combine(_parentRelPath, Path.GetFileName(_path)), _zipOutputStream, _zipCallback);
}
catch (System.Exception _e)
{
NRDebugger.Error("[ZipUtility.ZipDirectory]: " + _e.ToString());
return false;
}
string[] directories = Directory.GetDirectories(_path);
for (int index = 0; index < directories.Length; ++index)
{
if (!ZipDirectory(directories[index], Path.Combine(_parentRelPath, Path.GetFileName(_path)), _zipOutputStream, _zipCallback))
return false;
}
if (null != _zipCallback)
_zipCallback.OnPostZip(entry);
return true;
}
}
}