public static void CreateBarFile(IReadOnlyCollection <FileInfo> fileInfos, string inputPath, string outputFileName, string rootDir, bool ignoreLastWriteTime = true, bool xmlToXmb = true) { if (inputPath.EndsWith(Path.DirectorySeparatorChar.ToString())) { inputPath = inputPath.Substring(0, inputPath.Length - 1); } var folder = Path.GetDirectoryName(outputFileName); if (folder != null && !Directory.Exists(folder)) { Directory.CreateDirectory(folder); } var newFilesInfos = new List <FileInfo>(); foreach (var file in fileInfos.ToArray()) { if (file.FullName.EndsWith(".age4scn", StringComparison.OrdinalIgnoreCase)) { if (L33TZipUtils.IsL33TZip(file.FullName)) { var data = L33TZipUtils.DecompressL33TZip(file.FullName); File.Delete(file.FullName); File.WriteAllBytes(file.FullName, data); newFilesInfos.Add(new FileInfo(file.FullName)); } else { newFilesInfos.Add(file); } } else if (xmlToXmb && file.FullName.EndsWith(".quest", StringComparison.OrdinalIgnoreCase) || file.FullName.EndsWith(".region", StringComparison.OrdinalIgnoreCase) || file.FullName.EndsWith(".tactics", StringComparison.OrdinalIgnoreCase) || file.FullName.EndsWith(".character", StringComparison.OrdinalIgnoreCase) || file.FullName.EndsWith(".dataset", StringComparison.OrdinalIgnoreCase) || file.FullName.EndsWith(".empire", StringComparison.OrdinalIgnoreCase) || file.FullName.EndsWith(".spawneritem", StringComparison.OrdinalIgnoreCase) || file.FullName.EndsWith(".groupingset", StringComparison.OrdinalIgnoreCase) || file.FullName.EndsWith(".set", StringComparison.OrdinalIgnoreCase) || file.FullName.EndsWith(".xml", StringComparison.OrdinalIgnoreCase)) { if (XmbFile.IsXmlFile(file.FullName)) { XmbFileUtils.XmlFileToXmbFile(file.FullName, file.FullName + ".xmb"); File.Delete(file.FullName); newFilesInfos.Add(new FileInfo(file.FullName + ".xmb")); } else { newFilesInfos.Add(file); } } else { newFilesInfos.Add(file); } } using var fileStream = File.Open(outputFileName, FileMode.Create, FileAccess.Write, FileShare.None); using var writer = new BinaryWriter(fileStream); //Write Bar Header var header = new BarFileHeader(Path.GetFileName(outputFileName), newFilesInfos); writer.Write(header.ToByteArray()); //Write Files var barEntrys = new List <BarEntry>(); foreach (var file in newFilesInfos) { var filePath = file.FullName; barEntrys.Add(new BarEntry(inputPath, file, (int)writer.BaseStream.Position, ignoreLastWriteTime)); using var fileStream2 = File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.Read); using var binReader = new BinaryReader(fileStream2); var buffer = new byte[4096]; int read; while ((read = binReader.Read(buffer, 0, buffer.Length)) > 0) { writer.Write(buffer, 0, read); } } //Write Bar Entrys var end = new BarFileBody(rootDir, barEntrys); writer.Write(end.ToByteArray()); }
public static async Task <bool> ScanAndRepairFile(GameFileInfo fileInfo, string gameFilePath, IProgress <ScanSubProgress> progress = null, int concurrentDownload = 0, CancellationToken ct = default) { var filePath = Path.Combine(gameFilePath, fileInfo.FileName); //#1 Check File ct.ThrowIfCancellationRequested(); progress?.Report(new ScanSubProgress(ScanSubProgressStep.Check, 0)); Progress <double> subProgressCheck = null; if (progress != null) { subProgressCheck = new Progress <double>(); subProgressCheck.ProgressChanged += (o, d) => { progress.Report(new ScanSubProgress( ScanSubProgressStep.Check, d)); }; } if (await RunFileCheck(filePath, fileInfo.Size, fileInfo.Crc32, ct, subProgressCheck)) { progress?.Report(new ScanSubProgress(ScanSubProgressStep.End, 100)); return(true); } //#2 Download File ct.ThrowIfCancellationRequested(); progress?.Report(new ScanSubProgress(ScanSubProgressStep.Download, 0)); var tempFileName = Path.Combine(GameScannerTempPath, $"{fileInfo.FileName.GetHashCode():X4}.tmp"); if (File.Exists(tempFileName)) { File.Delete(tempFileName); } var fileDownloader = concurrentDownload == 1 ? (IFileDownloader) new SimpleFileDownloader(fileInfo.HttpLink, tempFileName) : new ChunkFileDownloader(fileInfo.HttpLink, tempFileName, GameScannerTempPath, concurrentDownload); if (progress != null) { fileDownloader.ProgressChanged += (sender, eventArg) => { switch (fileDownloader.State) { case FileDownloaderState.Invalid: case FileDownloaderState.Download: progress.Report(new ScanSubProgress( ScanSubProgressStep.Download, fileDownloader.DownloadProgress * 0.99, new ScanDownloadProgress(fileDownloader.DownloadSize, fileDownloader.BytesDownloaded, fileDownloader.DownloadSpeed))); break; case FileDownloaderState.Finalize: progress.Report(new ScanSubProgress( ScanSubProgressStep.Download, 99, new ScanDownloadProgress(fileDownloader.DownloadSize, fileDownloader.BytesDownloaded, 0))); break; case FileDownloaderState.Complete: progress.Report(new ScanSubProgress( ScanSubProgressStep.Download, 100, new ScanDownloadProgress(fileDownloader.DownloadSize, fileDownloader.BytesDownloaded, 0))); break; case FileDownloaderState.Error: case FileDownloaderState.Abort: break; default: throw new ArgumentOutOfRangeException(nameof(fileDownloader.State), fileDownloader.State, null); } } } ; await fileDownloader.DownloadAsync(ct); //#3 Check Downloaded File ct.ThrowIfCancellationRequested(); Progress <double> subProgressCheckDown = null; if (progress != null) { progress.Report(new ScanSubProgress(ScanSubProgressStep.CheckDownload, 0)); subProgressCheckDown = new Progress <double>(); subProgressCheckDown.ProgressChanged += (o, d) => { progress.Report(new ScanSubProgress( ScanSubProgressStep.CheckDownload, d)); }; } try { await EnsureValidGameFile(tempFileName, fileInfo.BinSize, fileInfo.BinCrc32, ct, subProgressCheckDown); } catch { if (File.Exists(tempFileName)) { File.Delete(tempFileName); } throw; } //#4 Extract downloaded file ct.ThrowIfCancellationRequested(); if (L33TZipUtils.IsL33TZip(tempFileName)) { var tempFileName2 = $"{tempFileName.Replace(".tmp", string.Empty)}.ext.tmp"; // Progress <double> extractProgress = null; if (progress != null) { progress.Report(new ScanSubProgress( ScanSubProgressStep.ExtractDownload, 0)); extractProgress = new Progress <double>(); extractProgress.ProgressChanged += (o, d) => { progress.Report(new ScanSubProgress( ScanSubProgressStep.ExtractDownload, d)); }; } await L33TZipUtils.DecompressL33TZipAsync(tempFileName, tempFileName2, extractProgress, ct); //#4.1 Check Extracted File ct.ThrowIfCancellationRequested(); Progress <double> subProgressCheckExt = null; if (progress != null) { progress.Report(new ScanSubProgress( ScanSubProgressStep.CheckExtractDownload, 0)); subProgressCheckExt = new Progress <double>(); subProgressCheckExt.ProgressChanged += (o, d) => { progress.Report(new ScanSubProgress( ScanSubProgressStep.CheckExtractDownload, d)); }; } await EnsureValidGameFile(tempFileName2, fileInfo.Size, fileInfo.Crc32, ct, subProgressCheckExt); File.Delete(tempFileName); tempFileName = tempFileName2; } //#5 Move new file to game folder ct.ThrowIfCancellationRequested(); progress?.Report(new ScanSubProgress( ScanSubProgressStep.Finalize, 0)); if (File.Exists(filePath)) { File.Delete(filePath); } else { var pathName = Path.GetDirectoryName(filePath); if (!string.IsNullOrEmpty(pathName) && !Directory.Exists(pathName)) { Directory.CreateDirectory(pathName); } } File.Move(tempFileName, filePath); //#6 End progress?.Report(new ScanSubProgress( ScanSubProgressStep.End, 100)); return(true); }
public static void ExtractBarFile(string inputFile, string file, string outputPath, bool convertFile = true) { if (string.IsNullOrWhiteSpace(file)) { throw new ArgumentNullException(nameof(file), "Value cannot be null or empty."); } if (!File.Exists(inputFile)) { throw new FileNotFoundException($"File '{inputFile}' not found!", inputFile); } if (!outputPath.EndsWith(Path.DirectorySeparatorChar.ToString())) { outputPath = outputPath + Path.DirectorySeparatorChar; } BarFileBody barFilesInfo; using (var fileStream = File.Open(inputFile, FileMode.Open, FileAccess.Read, FileShare.Read)) { using var binReader = new BinaryReader(fileStream); //Read Header binReader.BaseStream.Seek(0, SeekOrigin.Begin); //Seek to header var barFileHeader = new BarFileHeader(binReader); //Read Files Info binReader.BaseStream.Seek(barFileHeader.FilesTableOffset, SeekOrigin.Begin); //Seek to file table barFilesInfo = new BarFileBody(binReader); } var barFileInfo = barFilesInfo.Entries.First( key => string.Equals(key.FileName, file, StringComparison.OrdinalIgnoreCase)); using (var fileStream = File.Open(inputFile, FileMode.Open, FileAccess.Read, FileShare.Read)) { using var binReader = new BinaryReader(fileStream); binReader.BaseStream.Seek(barFileInfo.Offset, SeekOrigin.Begin); //Seek to file var path = Path.Combine(outputPath, barFilesInfo.RootPath, Path.GetDirectoryName(barFileInfo.FileName) ?? string.Empty); if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } var filePath = Path.Combine(outputPath, barFilesInfo.RootPath, barFileInfo.FileName); //Extract to tmp file var tempFileName = Path.GetTempFileName(); using (var fileStreamFinal = File.Open(tempFileName, FileMode.Create, FileAccess.Write, FileShare.None)) { using var final = new BinaryWriter(fileStreamFinal); var buffer = new byte[4096]; int read; var totalread = 0L; while ((read = binReader.Read(buffer, 0, buffer.Length)) > 0) { if (read > barFileInfo.FileSize) { totalread = barFileInfo.FileSize; final.Write(buffer, 0, barFileInfo.FileSize); } else if (totalread + read <= barFileInfo.FileSize) { totalread += read; final.Write(buffer, 0, read); } else if (totalread + read > barFileInfo.FileSize) { var leftToRead = barFileInfo.FileSize - totalread; totalread = barFileInfo.FileSize; final.Write(buffer, 0, Convert.ToInt32(leftToRead)); } if (totalread >= barFileInfo.FileSize) { break; } } } //Convert file if (convertFile) { //if (L33TZipUtils.IsL33TZip(tempFileName) && // !barFileInfo.FileName.EndsWith(".age4scn", StringComparison.OrdinalIgnoreCase)) //{ // var rnd = new Random(Guid.NewGuid().GetHashCode()); // var tempFileName2 = // Path.Combine(Path.GetTempPath(), // $"{Path.GetFileName(barFileInfo.FileName)}-{rnd.Next()}.tmp"); // L33TZipUtils.DecompressL33TZip(tempFileName, tempFileName2); // if (File.Exists(tempFileName)) // File.Delete(tempFileName); // tempFileName = tempFileName2; //} if (barFileInfo.FileName.EndsWith(".xmb", StringComparison.OrdinalIgnoreCase)) { try { var rnd = new Random(Guid.NewGuid().GetHashCode()); var tempFileName2 = Path.Combine(Path.GetTempPath(), $"{Path.GetFileName(barFileInfo.FileName)}-{rnd.Next()}.tmp"); XmbFileUtils.XmbFileToXmlFile(tempFileName, tempFileName2); if (File.Exists(tempFileName)) { File.Delete(tempFileName); } tempFileName = tempFileName2; filePath = filePath.Substring(0, filePath.Length - 4); } catch (Exception) { // } } else if (barFileInfo.FileName.EndsWith(".age4scn", StringComparison.OrdinalIgnoreCase) && !L33TZipUtils.IsL33TZip(tempFileName)) { var rnd = new Random(Guid.NewGuid().GetHashCode()); var tempFileName2 = Path.Combine(Path.GetTempPath(), $"{Path.GetFileName(barFileInfo.FileName)}-{rnd.Next()}.tmp"); L33TZipUtils.CompressFileAsL33TZipAsync(tempFileName, tempFileName2).GetAwaiter().GetResult(); if (File.Exists(tempFileName)) { File.Delete(tempFileName); } tempFileName = tempFileName2; } } //Move new file if (File.Exists(filePath)) { File.Delete(filePath); } // File.Move(tempFileName, filePath); // File.SetCreationTimeUtc(filePath, new DateTime(barFileInfo.LastWriteTime.Year, barFileInfo.LastWriteTime.Month, barFileInfo.LastWriteTime.Day, barFileInfo.LastWriteTime.Hour, barFileInfo.LastWriteTime.Minute, barFileInfo.LastWriteTime.Second)); File.SetLastWriteTimeUtc(filePath, new DateTime(barFileInfo.LastWriteTime.Year, barFileInfo.LastWriteTime.Month, barFileInfo.LastWriteTime.Day, barFileInfo.LastWriteTime.Hour, barFileInfo.LastWriteTime.Minute, barFileInfo.LastWriteTime.Second)); } }