mpq操作库
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 Debugprivate 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 Debugprivate 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
}
總結
- 上一篇: 极客时间es学习笔记
- 下一篇: DNS基础服务搭建