ProjectArcade
339 строк · 12.3 Кб
1using System;2using System.Collections.Generic;3using System.Linq;4using System.Text;5using System.Diagnostics;6using System.IO;7using System.Management;8using System.Runtime.InteropServices;9using System.IO.Compression;10using System.Security.Cryptography;11
12namespace EmulatorLauncher.Common13{
14public static class FileTools15{16/// <summary>17/// Get MD5 hash18/// </summary>19/// <param name="file"></param>20public static string GetMD5(string file)21{22if (!File.Exists(file))23return null;24
25using (var md5 = MD5.Create())26using (var stream = File.OpenRead(file))27return BitConverter.ToString(md5.ComputeHash(stream)).Replace("-", string.Empty).ToLower();28}29
30/// <summary>31/// Get SHA-1 hash32/// </summary>33/// <param name="file"></param>34public static string GetSHA1(string file)35{36if (!File.Exists(file))37return null;38
39using (FileStream fs = File.OpenRead(file))40{41SHA1 sha = new SHA1Managed();42return BitConverter.ToString(sha.ComputeHash(fs)).Replace("-", string.Empty).ToLower();43}44}45
46/// <summary>47/// Get File size48/// </summary>49/// <param name="file"></param>50public static long GetFileSize(string file)51{52if (!File.Exists(file))53return 0;54
55return new FileInfo(file).Length;56}57
58public static bool ExtractGZipBytes(byte[] bytes, string fileName)59{60try61{62using (var reader = new MemoryStream(bytes))63{64using (var decompressedStream = new FileStream(fileName, FileMode.Create, FileAccess.Write))65{66using (GZipStream decompressionStream = new GZipStream(reader, CompressionMode.Decompress))67{68decompressionStream.CopyTo(decompressedStream);69return true;70}71}72}73}74catch (Exception ex)75{76SimpleLogger.Instance.Error("[ReadGZipStream] Failed " + ex.Message, ex);77}78
79return false;80}81
82public static string GetRelativePath(string basePath, string targetPath)83{84Uri baseUri = new Uri(basePath);85Uri targetUri = new Uri(targetPath);86
87Uri relativeUri = baseUri.MakeRelativeUri(targetUri);88string relativePath = Uri.UnescapeDataString(relativeUri.ToString());89
90return relativePath.Replace('/', '\\');91}92
93public static string FindFreeDriveLetter()94{95var drives = DriveInfo.GetDrives();96
97for (char letter = 'Z'; letter >= 'D'; letter--)98if (!drives.Any(d => d.Name == letter + ":\\"))99return letter + ":\\";100
101return null;102}103
104private static void TryMoveFile(string sourceFileName, string destFileName)105{106if (File.Exists(sourceFileName))107{108if (File.Exists(destFileName))109{110try { File.Delete(destFileName); }111catch { }112}113
114try { File.Move(sourceFileName, destFileName); }115catch { }116}117}118
119public static void TryCreateDirectory(string path)120{121if (Directory.Exists(path))122return;123
124try { Directory.CreateDirectory(path); }125catch { }126}127
128public static void TryDeleteFile(string path)129{130if (!File.Exists(path))131return;132
133try { File.Delete(path); }134catch { }135}136
137public static void TryCopyFile(string sourceFileName, string destFileName, bool overwrite = true)138{139if (!File.Exists(sourceFileName))140return;141
142try { File.Copy(sourceFileName, destFileName, overwrite); }143catch { }144}145
146#region Apis147const uint GENERIC_READ = 0x80000000;148const uint GENERIC_WRITE = 0x40000000;149const uint OPEN_EXISTING = 3;150const uint FILE_SHARE_READ = 1;151const uint FILE_SHARE_WRITE = 2;152
153static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);154
155[DllImport("kernel32.dll", SetLastError = true)]156static extern IntPtr CreateFile(157string lpFileName,158uint dwDesiredAccess,159uint dwShareMode,160IntPtr lpSecurityAttributes,161uint dwCreationDisposition,162uint dwFlagsAndAttributes,163IntPtr hTemplateFile164);165
166[DllImport("kernel32.dll", SetLastError = true)]167[return: MarshalAs(UnmanagedType.Bool)]168static extern bool CloseHandle(IntPtr hObject);169#endregion170
171public static bool IsFileLocked(string path)172{173if (!File.Exists(path))174return false;175
176IntPtr handle = CreateFile(path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);177if (handle == INVALID_HANDLE_VALUE)178return true;179
180CloseHandle(handle);181return false;182}183
184public static void CopyDirectory(string sourceDir, string destinationDir, bool recursive)185{186// Get information about the source directory187var dir = new DirectoryInfo(sourceDir);188
189// Check if the source directory exists190if (!dir.Exists)191throw new DirectoryNotFoundException("Source directory not found: " + dir.FullName);192
193// Cache directories before we start copying194DirectoryInfo[] dirs = dir.GetDirectories();195
196// Create the destination directory197Directory.CreateDirectory(destinationDir);198
199// Get the files in the source directory and copy to the destination directory200foreach (FileInfo file in dir.GetFiles())201{202string targetFilePath = Path.Combine(destinationDir, file.Name);203file.CopyTo(targetFilePath);204}205
206// If recursive and copying subdirectories, recursively call this method207if (recursive)208{209foreach (DirectoryInfo subDir in dirs)210{211string newDestinationDir = Path.Combine(destinationDir, subDir.Name);212CopyDirectory(subDir.FullName, newDestinationDir, true);213}214}215}216
217public static void CreateSymlink(string destinationLink, string pathToLink, bool directory = true)218{219string workingDirectory = Path.GetDirectoryName(destinationLink);220string directoryName = Path.GetFileName(destinationLink);221
222var psi = new ProcessStartInfo("cmd.exe", directory ?223"/C mklink /J \"" + directoryName + "\" \"" + pathToLink + "\"" :224"/C mklink \"" + directoryName + "\" \"" + pathToLink + "\"");225psi.WorkingDirectory = workingDirectory;226psi.CreateNoWindow = true;227psi.UseShellExecute = false;228Process.Start(psi).WaitForExit();229}230
231public static void CompressDirectory(string _outputFolder)232{233var dir = new DirectoryInfo(_outputFolder);234
235if (!dir.Exists)236{237dir.Create();238}239
240if ((dir.Attributes & FileAttributes.Compressed) == 0)241{242try243{244// Enable compression for the output folder245// (this will save a ton of disk space)246
247string objPath = "Win32_Directory.Name=" + "'" + dir.FullName.Replace("\\", @"\\").TrimEnd('\\') + "'";248
249using (ManagementObject obj = new ManagementObject(objPath))250{251using (obj.InvokeMethod("Compress", null, null))252{253// I don't really care about the return value,254// if we enabled it great but it can also be done manually255// if really needed256}257}258}259catch (Exception ex)260{261System.Diagnostics.Trace.WriteLine("Cannot enable compression for folder '" + dir.FullName + "': " + ex.Message, "WMI");262}263}264}265
266[DllImport("shell32.dll")]267public static extern bool SHGetSpecialFolderPath(IntPtr hwndOwner, [Out]StringBuilder lpszPath, int nFolder, bool fCreate);268
269public static string GetSystemDirectory()270{271if (Environment.Is64BitOperatingSystem)272{273StringBuilder path = new StringBuilder(260);274SHGetSpecialFolderPath(IntPtr.Zero, path, 0x0029, false); // CSIDL_SYSTEMX86275return path.ToString();276}277
278return Environment.SystemDirectory;279}280
281public static string GetShortcutTarget(string file)282{283try284{285if (System.IO.Path.GetExtension(file).ToLower() != ".lnk")286{287throw new Exception("Supplied file must be a .LNK file");288}289
290FileStream fileStream = File.Open(file, FileMode.Open, FileAccess.Read);291using (System.IO.BinaryReader fileReader = new BinaryReader(fileStream))292{293fileStream.Seek(0x14, SeekOrigin.Begin); // Seek to flags294uint flags = fileReader.ReadUInt32(); // Read flags295if ((flags & 1) == 1)296{ // Bit 1 set means we have to297// skip the shell item ID list298fileStream.Seek(0x4c, SeekOrigin.Begin); // Seek to the end of the header299uint offset = fileReader.ReadUInt16(); // Read the length of the Shell item ID list300fileStream.Seek(offset, SeekOrigin.Current); // Seek past it (to the file locator info)301}302
303long fileInfoStartsAt = fileStream.Position; // Store the offset where the file info304// structure begins305uint totalStructLength = fileReader.ReadUInt32(); // read the length of the whole struct306fileStream.Seek(0xc, SeekOrigin.Current); // seek to offset to base pathname307uint fileOffset = fileReader.ReadUInt32(); // read offset to base pathname308// the offset is from the beginning of the file info struct (fileInfoStartsAt)309fileStream.Seek((fileInfoStartsAt + fileOffset), SeekOrigin.Begin); // Seek to beginning of310// base pathname (target)311long pathLength = (totalStructLength + fileInfoStartsAt) - fileStream.Position - 2; // read312// the base pathname. I don't need the 2 terminating nulls.313char[] linkTarget = fileReader.ReadChars((int)pathLength); // should be unicode safe314var link = new string(linkTarget);315
316int begin = link.IndexOf("\0\0");317if (begin > -1)318{319int end = link.IndexOf("\\\\", begin + 2) + 2;320end = link.IndexOf('\0', end) + 1;321
322string firstPart = link.Substring(0, begin);323string secondPart = link.Substring(end);324
325return firstPart + secondPart;326}327else328{329return link;330}331}332}333catch334{335return "";336}337}338}339}
340