public static List <LogInfo> Expand(EngineState s, CodeCommand cmd) { List <LogInfo> logs = new List <LogInfo>(); CodeInfo_Expand info = cmd.Info.Cast <CodeInfo_Expand>(); List <string> extractedFiles = new List <string>(); #region Event Handlers void ReportExpandProgress(object sender, ProgressEventArgs e) { s.MainViewModel.BuildCommandProgressValue = e.PercentDone; s.MainViewModel.BuildCommandProgressText = $"Expanding... ({e.PercentDone}%)"; } object trackLock = new object(); void TrackExtractedFile(object sender, FileInfoEventArgs e) { lock (trackLock) extractedFiles.Add(e.FileInfo.FileName); } #endregion string srcCab = StringEscaper.Preprocess(s, info.SrcCab); string destDir = StringEscaper.Preprocess(s, info.DestDir); string singleFile = null; if (info.SingleFile != null) { singleFile = StringEscaper.Preprocess(s, info.SingleFile); } // Path Security Check if (!StringEscaper.PathSecurityCheck(destDir, out string errorMsg)) { return(LogInfo.LogErrorMessage(logs, errorMsg)); } if (!Directory.Exists(destDir)) { if (File.Exists(destDir)) { return(LogInfo.LogErrorMessage(logs, $"Path [{destDir}] is a file, not a directory")); } Directory.CreateDirectory(destDir); } // Does srcCab exist? if (!File.Exists(srcCab)) { return(LogInfo.LogErrorMessage(logs, $"Cannot find [{srcCab}]")); } // Turn on report progress only if file is larger than 1MB FileInfo fi = new FileInfo(srcCab); bool reportProgress = 1024 * 1024 <= fi.Length; if (singleFile == null) { // No singleFile operand, extract all using (SevenZipExtractor extractor = new SevenZipExtractor(srcCab)) { if (extractor.Format != InArchiveFormat.Cab) { return(LogInfo.LogErrorMessage(logs, "Expand command must be used with cabinet archive")); } if (reportProgress) { extractor.FileExtractionFinished += TrackExtractedFile; extractor.Extracting += ReportExpandProgress; s.MainViewModel.SetBuildCommandProgress("Expand Progress"); } try { extractor.ExtractArchive(destDir); foreach (string file in extractedFiles) { logs.Add(new LogInfo(LogState.Success, $"[{file}] extracted")); } logs.Add(new LogInfo(LogState.Success, $"[{extractedFiles.Count}] files from [{srcCab}] extracted to [{destDir}]")); } finally { if (reportProgress) { extractor.FileExtractionFinished -= TrackExtractedFile; extractor.Extracting -= ReportExpandProgress; s.MainViewModel.ResetBuildCommandProgress(); } } } } else { // singleFile specified, extract only that file string destPath = Path.Combine(destDir, singleFile); if (File.Exists(destPath)) { // Check PRESERVE, NOWARN if (info.Preserve) { // Do nothing logs.Add(new LogInfo(info.NoWarn ? LogState.Ignore : LogState.Overwrite, $"[{destPath}] already exists, skipping extract from [{srcCab}]")); return(logs); } logs.Add(new LogInfo(info.NoWarn ? LogState.Ignore : LogState.Overwrite, $"[{destPath}] will be overwritten")); } using (SevenZipExtractor extractor = new SevenZipExtractor(srcCab)) { if (extractor.Format != InArchiveFormat.Cab) { return(LogInfo.LogErrorMessage(logs, "Expand command must be used with cabinet archive")); } if (reportProgress) { extractor.Extracting += ReportExpandProgress; s.MainViewModel.SetBuildCommandProgress("Expand Progress"); } string[] archiveFileNames = extractor.ArchiveFileNames.ToArray(); if (archiveFileNames.Contains(singleFile, StringComparer.OrdinalIgnoreCase)) { try { string destFile = Path.Combine(destDir, singleFile); using (FileStream fs = new FileStream(destFile, FileMode.Create)) { extractor.ExtractFile(singleFile, fs); } logs.Add(new LogInfo(LogState.Success, $"[{singleFile}] from [{srcCab}] extracted to [{destPath}]")); } finally { if (reportProgress) { extractor.Extracting -= ReportExpandProgress; s.MainViewModel.ResetBuildCommandProgress(); } } } else { // Unable to find specified file logs.Add(new LogInfo(LogState.Error, $"Failed to extract [{singleFile}] from [{srcCab}]")); } } } return(logs); }
public static List <LogInfo> Expand(EngineState s, CodeCommand cmd) { List <LogInfo> logs = new List <LogInfo>(); Debug.Assert(cmd.Info.GetType() == typeof(CodeInfo_Expand)); CodeInfo_Expand info = cmd.Info as CodeInfo_Expand; string srcCab = StringEscaper.Preprocess(s, info.SrcCab); string destDir = StringEscaper.Preprocess(s, info.DestDir); string singleFile = null; if (info.SingleFile != null) { singleFile = StringEscaper.Preprocess(s, info.SingleFile); } // Path Security Check if (StringEscaper.PathSecurityCheck(destDir, out string errorMsg) == false) { logs.Add(new LogInfo(LogState.Error, errorMsg)); return(logs); } if (!Directory.Exists(destDir)) { if (File.Exists(destDir)) { logs.Add(new LogInfo(LogState.Error, $"Path [{destDir}] is file, not a directory")); return(logs); } Directory.CreateDirectory(destDir); } if (singleFile == null) { // No singleFile operand, extract all if (ArchiveHelper.ExtractCab(srcCab, destDir, out List <string> doneList)) // Success { foreach (string done in doneList) { logs.Add(new LogInfo(LogState.Success, $"[{done}] extracted")); } logs.Add(new LogInfo(LogState.Success, $"[{doneList.Count}] files from [{srcCab}] extracted to [{destDir}]")); } else // Failure { logs.Add(new LogInfo(LogState.Error, $"Failed to extract [{srcCab}]")); } } else { // singleFile specified, extract only that singleFile string destPath = Path.Combine(destDir, singleFile); if (File.Exists(destPath)) { // Check PRESERVE, NOWARN if (info.Preserve) { // Do nothing logs.Add(new LogInfo(info.NoWarn ? LogState.Ignore : LogState.Warning, $"[{destPath}] already exists, cannot extract from [{srcCab}]")); return(logs); } else { logs.Add(new LogInfo(info.NoWarn ? LogState.Ignore : LogState.Warning, $"[{destPath}] will be overwritten")); } } if (ArchiveHelper.ExtractCab(srcCab, destDir, singleFile)) // Success { logs.Add(new LogInfo(LogState.Success, $"[{singleFile}] from [{srcCab}] extracted to [{destPath}]")); } else // Failure { logs.Add(new LogInfo(LogState.Error, $"Failed to extract [{singleFile}] from [{srcCab}]")); } } return(logs); }