using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.Reflection;
/// <summary>
/// 档案
/// </summary>
public class Archive : IDisposable
{
#region api声明
[DllImport("StormLib.dll", EntryPoint = "SFileAddFileEx", SetLastError = true)]
private static extern bool SFileAddFileEx(IntPtr hMpq, string szFileName, string szArchivedName, uint dwFlags, uint dwCompression, uint CompressionNext);
[DllImport("StormLib.dll", EntryPoint = "SFileCloseArchive", SetLastError = true)]
private static extern bool SFileCloseArchive(IntPtr hMpq);
[DllImport("StormLib.dll", EntryPoint = "SFileCompactArchive", SetLastError = true)]
private static extern bool SFileCompactArchive(IntPtr hMpq, string szListFile, bool bReserved);
[DllImport("StormLib.dll", EntryPoint = "SFileCreateArchive", SetLastError = true)]
private static extern bool SFileCreateArchive(string szMpqName, uint dwFlags, uint dwMaxFileCount, out IntPtr phMPQ);
[DllImport("StormLib.dll", EntryPoint = "SFileGetFileInfo", SetLastError = true)]
private static extern bool SFileGetFileInfo(IntPtr hMpqOrFile, uint dwInfoType, StringBuilder pvFileInfo, int cbFileInfo, out uint pcbLengthNeeded);
[DllImport("StormLib.dll", EntryPoint = "SFileGetFileInfo", SetLastError = true)]
private static extern bool SFileGetFileInfo(IntPtr hMpqOrFile, uint dwInfoType, ref uint pvFileInfo, uint cbFileInfo, out uint pcbLengthNeeded);
[DllImport("StormLib.dll", EntryPoint = "SFileHasFile", SetLastError = true)]
private static extern bool SFileHasFile(IntPtr hMpq, string szFileName);
[DllImport("StormLib.dll", EntryPoint = "SFileOpenArchive", SetLastError = true)]
private static extern bool SFileOpenArchive(string szMpqName, uint dwPriority, uint dwFlags, out IntPtr phMPQ);
[DllImport("StormLib.dll", EntryPoint = "SFileRemoveFile", SetLastError = true)]
private static extern bool SFileRemoveFile(IntPtr hMpq, string szFileName, uint dwSearchScope);
[DllImport("StormLib.dll", EntryPoint = "SFileRenameFile", SetLastError = true)]
private static extern bool SFileRenameFile(IntPtr hMpq, string szOldFileName, string szNewFileName);
#endregion
#region 常量
/// <summary>
/// 压缩
/// </summary>
private const uint MPQ_FILE_COMPRESS = 0x200;
/// <summary>
/// 允许覆盖
/// </summary>
private const uint MPQ_FILE_REPLACEEXISTING = 0x80000000;
/// 读取mpq名字
/// </summary>
private const uint SFILE_INFO_ARCHIVE_NAME = 1;
/// <summary>
/// 读取mpq大小
/// </summary>
private const uint SFILE_INFO_ARCHIVE_SIZE = 2;
#endregion
#region 属性
/// <summary>
/// 档案的句柄
/// </summary>
private IntPtr hArchive = IntPtr.Zero;
public IntPtr HArchive
{
get
{
return this.hArchive;
}
}
/// <summary>
/// listfile的列表
/// </summary>
private List<string> listfile = new List<string>();
public List<string> Listfile
{
get
{
return this.listfile;
}
}
#endregion
#region 构造函数
/// <summary>
/// 构造函数
/// </summary>
/// <param name="archivePath">档案路径</param>
public Archive(string archivePath)
{
if (File.Exists(archivePath) == true)// 档案文件存在,尝试打开文件
{
if (SFileOpenArchive(archivePath, 0, 0, out this.hArchive) == true)// 打开成功
{
if (FileExists("(listfile)") == true)// 存在文件列表
{
if (LoadListFile() == true)// 加载文件列表成功
{
}
else// 加载文件列表失败
{
this.Dispose();
MessageBox.Show("读取文件列表失败");
}
}
else// 不存在文件列表
{
this.Dispose();
MessageBox.Show("找不到文件列表");
}
}
else// 打开失败
{
this.hArchive = IntPtr.Zero;
this.ShowError();
}
}
else// 档案文件不存在,创建档案文件
{
if (SFileCreateArchive(archivePath, 0, 0x80000, out this.hArchive) == true)// 创建成功
{
}
else// 创建失败
{
this.hArchive = IntPtr.Zero;
this.ShowError();
}
}
}
#endregion
#region 公开方法
/// <summary>
/// 添加文件到档案中
/// </summary>
/// <param name="localPath">本地路径</param>
/// <param name="archivePath">档案中需显示的路径</param>
/// <returns>成功则返回true,失败返回false</returns>
public bool AddFileWithPath(string localPath, string archivePath)
{
if (SFileAddFileEx(this.hArchive, localPath, archivePath, MPQ_FILE_COMPRESS | MPQ_FILE_REPLACEEXISTING, 0, 0) == true)// 添加成功
{
listfile.Add(archivePath);
return true;
}
else// 添加失败
{
ShowError();
return false;
}
}
/// <summary>
/// 关闭档案
/// </summary>
public void Dispose()
{
if (this.hArchive != IntPtr.Zero)// 之前打开或创建成功
{
if (SFileCloseArchive(this.hArchive) == true)// 关闭成功
{
this.hArchive = IntPtr.Zero;
}
else// 关闭失败
{
this.hArchive = IntPtr.Zero;
this.ShowError();
}
}
}
/// <summary>
/// 解压文件
/// </summary>
/// <param name="filePath">文件在档案中的路径</param>
/// <param name="localPath">本地路径</param>
/// <returns>成功则返回true,失败返回flase</returns>
public bool ExtractFile(string filePath, string localPath)
{
using (ArchiveFile file = this.OpenFile(filePath))// 打开文件
{
uint fileSize = file.GetSize();// 获取文件大小
if (fileSize == uint.MaxValue)// 获取失败
{
return false;
}
else// 获取成功
{
if (fileSize == 0)// 空文件
{
try
{
File.Create(localPath).Dispose();// 创建空文件
}
catch (Exception ex)
{
MessageBox.Show("创建文件失败\n" + ex.ToString());
return false;
}
return true;
}
else// 非空文件
{
byte[] bytes = file.ReadAllBytes();// 读取文件
if (bytes.Length != 0)// 读取成功
{
FileStream fs;
try
{
fs = File.Create(localPath);// 创建本地文件
}
catch
{
return false;// 创建本地文件失败
}
fs.Write(bytes, 0, bytes.Length);// 写入到本地文件
fs.Dispose();
return true;
}
else// 读取失败
{
return false;
}
}
}
}
}
/// <summary>
/// 档案中是否存在文件
/// </summary>
/// <param name="filePath">文件路径</param>
/// <returns>存在则返回true,否则返回false</returns>
public bool FileExists(string filePath)
{
if (SFileHasFile(this.hArchive, filePath) == true)// 存在
{
return true;
}
else// 不存在
{
return false;
}
}
/// <summary>
/// 获取档案名字
/// </summary>
/// <returns>成功返回档案的名字,失败则返回空字符串</returns>
public string GetName()
{
StringBuilder sb = new StringBuilder(string.Empty, 260);
uint nameLength;// 读取出的名字长度
if (SFileGetFileInfo(this.hArchive, SFILE_INFO_ARCHIVE_NAME, sb, sb.Capacity, out nameLength) == true)// 获取成功
{
return sb.ToString();
}
else// 获取失败
{
ShowError();
return string.Empty;
}
}
/// <summary>
/// 获取档案大小
/// </summary>
/// <returns>成功返回档案的大小(字节),失败则返回0</returns>
public uint GetSize()
{
uint archiveSize = 0, length;
if (SFileGetFileInfo(this.hArchive, SFILE_INFO_ARCHIVE_SIZE, ref archiveSize, sizeof(uint), out length) == true)// 获取成功
{
return archiveSize;
}
else// 获取失败
{
ShowError();
return 0;
}
}
/// <summary>
/// 打开档案中的一个文件
/// </summary>
/// <param name="filePath">文件路径</param>
/// <returns>文件句柄</returns>
public ArchiveFile OpenFile(string filePath)
{
return new ArchiveFile(this.hArchive, filePath);
}
/// <summary>
/// 重压缩档案
/// </summary>
/// <returns>成功则返回true,否则返回false</returns>
public bool ReCompress()
{
if (SFileCompactArchive(this.hArchive, null, false) == true)// 重压缩成功
{
return true;
}
else// 重压缩失败
{
ShowError();
return false;
}
}
/// <summary>
/// 删除档案中的文件
/// </summary>
/// <param name="filePath">文件路径</param>
/// <returns>成功则返回true,否则返回false</returns>
public bool RemoveFile(string filePath)
{
if (FileExists(filePath) == true)// 文件存在
{
if (SFileRemoveFile(this.hArchive, filePath, 0) == true)// 删除成功
{
listfile.Remove("filePath");
return true;
}
else// 删除失败
{
ShowError();
return false;
}
}
else// 文件不存在
{
return false;
}
}
/// <summary>
/// 重命名档案中的文件
/// </summary>
/// <param name="oldPath">文件路径</param>
/// <param name="newPath">新的文件路径</param>
/// <returns>成功则返回true,否则返回false</returns>
public bool RenameFile(string oldPath, string newPath)
{
if (FileExists(oldPath) == true)// 文件存在
{
if (FileExists(newPath) == false)// 新文件不存在
{
if (SFileRenameFile(this.hArchive, oldPath, newPath))// 重命名成功
{
listfile.Remove(oldPath);
listfile.Add(newPath);
return true;
}
else// 重命名失败
{
ShowError();
return false;
}
}
else// 已存在新文件
{
return false;
}
}
else// 文件不存在
{
return false;
}
}
#endregion
#region 私有方法
/// <summary>
/// 获取listfile的内容
/// </summary>
/// <returns>成功则返回true,失败返回false</returns>
private bool LoadListFile()
{
using (ArchiveFile hlistfile = this.OpenFile("(listfile)"))// 打开listfile
{
if (hlistfile.HFile.ToInt32() == 0)// 打开失败
{
return false;
}
else// 打开成功
{
string[] str = hlistfile.ReadAllLines();
if (str.Length == 0)// 读取失败
{
return false;
}
else// 读取成功
{
this.listfile = new List<string>(str);// 将文件列表保存
return true;
}
}
}
}
#endregion
#region Debug
private int LastWin32Error = 0;
private void ShowError()
{
LastWin32Error = Marshal.GetLastWin32Error();
StackTrace ss = new StackTrace(true);
MethodBase mb = ss.GetFrame(1).GetMethod();
MessageBox.Show("function:" + mb.Name + "\nerror:" + LastWin32Error.ToString());
}
#endregion
}
/// <summary>
/// 档案文件
/// </summary>
public class ArchiveFile : IDisposable
{
#region api声明
[DllImport("StormLib.dll", EntryPoint = "SFileCloseFile", SetLastError = true)]
private static extern bool SFileCloseFile(IntPtr hFile);
[DllImport("StormLib.dll", EntryPoint = "SFileGetFileName", SetLastError = true)]
private static extern bool SFileGetFileName(IntPtr hFile, StringBuilder szFileName);
[DllImport("StormLib.dll", EntryPoint = "SFileGetFileSize", SetLastError = true)]
private static extern uint SFileGetFileSize(IntPtr hFile, out uint pdwFileSizeHigh);
[DllImport("StormLib.dll", EntryPoint = "SFileOpenFileEx", SetLastError = true)]
private static extern bool SFileOpenFileEx(IntPtr hMPQ, string szFileName, uint dwSearchScope, out IntPtr phFile);
[DllImport("StormLib.dll", EntryPoint = "SFileReadFile", SetLastError = true)]
private static extern bool SFileReadFile(IntPtr hFile, byte[] lpBuffer, uint dwToRead, out uint pdwRead, ref OVERLAPPED lpOverlapped);
[DllImport("StormLib.dll", EntryPoint = "SFileRenameFile", SetLastError = true)]
private static extern bool SFileRenameFile(IntPtr hMpq, string szOldFileName, string szNewFileName);
#endregion
#region 常量
#endregion
#region 属性
/// <summary>
/// 文件句柄
/// </summary>
private IntPtr hFile = IntPtr.Zero;
public IntPtr HFile
{
get
{
return this.hFile;
}
}
/// <summary>
/// 维持堆栈平衡
/// </summary>
private struct OVERLAPPED
{
public uint Internal;
public uint InternalHigh;
public uint Offset;
public uint OffsetHigh;
public IntPtr hEvent;
}
#endregion
#region 构造函数
/// <summary>
/// 构造函数
/// </summary>
/// <param name="hArchive">档案的句柄</param>
/// <param name="filePath">文件的路径</param>
public ArchiveFile(IntPtr hArchive, string filePath)
{
if (SFileOpenFileEx(hArchive, filePath, 0, out this.hFile) == true)// 打开成功
{
}
else// 打开失败
{
this.hFile = IntPtr.Zero;
this.ShowError();
}
}
#endregion
#region 公开方法
/// <summary>
/// 关闭文件
/// </summary>
public void Dispose()
{
if (this.hFile != IntPtr.Zero)// 之前打开成功
{
if (SFileCloseFile(this.hFile) == true)// 关闭成功
{
this.hFile = IntPtr.Zero;
}
else// 关闭失败
{
this.hFile = IntPtr.Zero;
this.ShowError();
}
}
}
/// <summary>
/// 获取文件名
/// </summary>
/// <returns>文件的名字</returns>
public string GetName()
{
StringBuilder sb = new StringBuilder(260);
if (SFileGetFileName(this.hFile, sb) == true)// 获取成功
{
return sb.ToString();
}
else// 获取失败
{
return string.Empty;
}
}
/// <summary>
/// 获取文件大小
/// </summary>
/// <returns>成功则返回文件总共多少字节,否则返回SFILE_INVALID_SIZE(4294967295)无符号整数十进制最大值</returns>
public uint GetSize()
{
uint fileSize, fileSizeHigh;
fileSize = SFileGetFileSize(this.hFile, out fileSizeHigh);
if (fileSize != uint.MaxValue)// 获取成功
{
return fileSize;
}
else// 获取失败
{
this.ShowError();
return fileSize;
}
}
/// <summary>
/// 读取文件中的所有字节
/// </summary>
/// <returns>成功则返回文件内容,失败返回空字节数组</returns>
public byte[] ReadAllBytes()
{
uint fileSize = GetSize();
if (fileSize == uint.MaxValue)// 获取文件大小失败
{
return new byte[0];
}
else// 获取文件大小成功
{
if (fileSize == 0)// 文件长度为0,即为空文件
{
return new byte[0];
}
else// 文件长度不为0
{
byte[] buffer = new byte[fileSize];// 缓冲
uint readLength;// 读取出的长度
OVERLAPPED overlapped = new OVERLAPPED();// 维持堆栈平衡
if (SFileReadFile(this.hFile, buffer, fileSize, out readLength, ref overlapped) == true)// 读取成功
{
return buffer;
}
else// 读取失败
{
this.ShowError();
return new byte[0];
}
}
}
}
/// <summary>
/// 以UTF-8编码读取文件中的所有行
/// </summary>
/// <returns>成功则返回文件所有行,失败则返回空字符串数组</returns>
public string[] ReadAllLines()
{
string str = ReadAllText();// 读取内容
if (str == string.Empty)// 读取失败
{
return new string[0];
}
else// 读取成功
{
return str.Split('\r', '\n');
}
}
/// <summary>
/// 以UTF-8编码读取文件中的所有内容
/// </summary>
/// <returns>成功则返回文件内容,失败返回空字符串</returns>
public string ReadAllText()
{
byte[] bytes = this.ReadAllBytes();
if (bytes.Length != 0)// 读取成功
{
return Encoding.UTF8.GetString(bytes);// 解码
}
else// 读取失败
{
return string.Empty;
}
}
#endregion
#region 私有方法
#endregion
#region Debug
private int LastWin32Error = 0;
private void ShowError()
{
LastWin32Error = Marshal.GetLastWin32Error();
StackTrace ss = new StackTrace(true);
MethodBase mb = ss.GetFrame(1).GetMethod();
MessageBox.Show("function:" + mb.Name + "\nerror:" + LastWin32Error.ToString());
}
#endregion
}
mpq操作库
最新推荐文章于 2019-06-02 02:56:00 发布