/// <summary> /// Reads a single file from a cabinet stream. /// </summary> /// <param name="stream">Stream for reading the cabinet file.</param> /// <param name="name">Name of the file within the cabinet (not the external file path).</param> /// <returns>A stream for reading the extracted file, or null if the file does not exist in the cabinet.</returns> /// <exception cref="CabinetExtractException">The stream is not a cabinet file or the cabinet file is corrupt.</exception> /// <remarks>This method may fail if the file size is greater than available memory.</remarks> public static Stream Extract(Stream stream, string name) { if (stream == null) { throw new ArgumentNullException("stream"); } return(Cabinet.Extract(new CabinetOpenCabHandler(Cabinet.DefaultOpenCabHandler), new CabinetCloseCabHandler(Cabinet.DefaultCloseCabHandler), stream, false, name)); }
/// <summary> /// Extracts all files from a cabinet to a destination directory, optionally extracting only newer files. /// </summary> /// <param name="destDirectory">Directory where the files are to be extracted.</param> /// <param name="update">Specify true to only extract files when the timestamp in the cabinet is newer than /// the timestamp of the file on disk, when the file already exists.</param> /// <param name="callback">Handler for receiving progress information; this may be null if progress is not desired.</param> /// <param name="context">User context object passed to the <paramref name="callback"/>, may be null.</param> internal virtual void ExtractAll(string destDirectory, bool update, CabinetStatusCallback callback, object context) { using (Stream stream = this.GetCabinetReadStream()) { object[] fileContext = new Object[] { destDirectory, null, update }; Cabinet.Extract(stream, new CabinetExtractOpenFileHandler(CabinetInfo.ExtractOpenFileHandler), new CabinetExtractCloseFileHandler(CabinetInfo.ExtractCloseFileHandler), fileContext, null, null, callback, context); } }
private void ExtractFilesFromMergeModule(IMsmMerge2 merge, WixMergeSymbol wixMergeRow) { var moduleOpen = false; short mergeLanguage; var mergeId = wixMergeRow.Id.Id; try { mergeLanguage = Convert.ToInt16(wixMergeRow.Language, CultureInfo.InvariantCulture); } catch (FormatException) { this.Messaging.Write(ErrorMessages.InvalidMergeLanguage(wixMergeRow.SourceLineNumbers, mergeId, wixMergeRow.Language.ToString())); return; } try { merge.OpenModule(wixMergeRow.SourceFile, mergeLanguage); moduleOpen = true; // extract the module cabinet, then explode all of the files to a temp directory var moduleCabPath = Path.Combine(this.IntermediateFolder, mergeId + ".cab"); merge.ExtractCAB(moduleCabPath); var mergeIdPath = Path.Combine(this.IntermediateFolder, mergeId); Directory.CreateDirectory(mergeIdPath); try { var cabinet = new Cabinet(moduleCabPath); cabinet.Extract(mergeIdPath); } catch (FileNotFoundException) { throw new WixException(ErrorMessages.CabFileDoesNotExist(moduleCabPath, wixMergeRow.SourceFile, mergeIdPath)); } catch { throw new WixException(ErrorMessages.CabExtractionFailed(moduleCabPath, wixMergeRow.SourceFile, mergeIdPath)); } } catch (COMException ce) { throw new WixException(ErrorMessages.UnableToOpenModule(wixMergeRow.SourceLineNumbers, wixMergeRow.SourceFile, ce.Message)); } finally { if (moduleOpen) { merge.CloseModule(); } } }
/// <summary> /// Extracts multiple files from the cabinet. If any extracted files already exist on disk, they will be overwritten. /// </summary> /// <param name="filenameMap">A mapping from internal file paths to external file paths. /// Case-senstivity when matching internal paths depends on the IDictionary implementation.</param> /// <param name="destDirectory">This parameter may be null, but if specified it is the root directory /// for any relative external paths in <paramref name="filenameMap"/>.</param> /// <param name="update">Specify true to only extract files when the timestamp in the cabinet is newer than /// the timestamp of the file on disk, when the file already exists.</param> /// <param name="callback">Handler for receiving progress information; this may be null if progress is not desired.</param> /// <param name="context">User context object passed to the <paramref name="callback"/>, may be null.</param> internal virtual void ExtractFileSet(IDictionary filenameMap, string destDirectory, bool update, CabinetStatusCallback callback, Object context) { if (filenameMap == null) { throw new ArgumentNullException("filenameMap"); } using (Stream stream = this.GetCabinetReadStream()) { object[] fileContext = new Object[] { destDirectory, filenameMap, update }; Cabinet.Extract(stream, new CabinetExtractOpenFileHandler(CabinetInfo.ExtractOpenFileHandler), new CabinetExtractCloseFileHandler(CabinetInfo.ExtractCloseFileHandler), fileContext, new CabinetFilterFileHandler(this.FilterFileHandler), filenameMap, callback, context); } }
public void IntegrationTest() { using (var fs = new DisposableFileSystem()) { var intermediateFolder = fs.GetFolder(true); var cabinetPath = Path.Combine(intermediateFolder, "testout.cab"); var extractFolder = fs.GetFolder(true); // Compress. { var files = new[] { new CabinetCompressFile(TestData.Get(@"TestData\test.txt"), "test1.txt"), new CabinetCompressFile(TestData.Get(@"TestData\test.txt"), "test2.txt"), }; var cabinet = new Cabinet(cabinetPath); cabinet.Compress(files, CompressionLevel.Low); } // Extract. { var cabinet = new Cabinet(cabinetPath); var reportedFiles = cabinet.Extract(extractFolder); Assert.Equal(2, reportedFiles.Count()); } // Enumerate to compare cabinet to extracted files. { var cabinet = new Cabinet(cabinetPath); var enumerated = cabinet.Enumerate().OrderBy(f => f.FileId).ToArray(); var files = Directory.EnumerateFiles(extractFolder).OrderBy(f => f).ToArray(); for (var i = 0; i < enumerated.Length; ++i) { var cabFileInfo = enumerated[i]; var fileInfo = new FileInfo(files[i]); Assert.Equal(cabFileInfo.FileId, fileInfo.Name); Assert.Equal(cabFileInfo.Size, fileInfo.Length); Assert.True(cabFileInfo.SameAsDateTime(fileInfo.CreationTime)); } } } }
/// <summary> /// Extracts files from a cabinet stream. /// </summary> /// <param name="stream">Stream for reading the cabinet file.</param> /// <param name="openFileHandler">Callback for opening streams for writing extracted files.</param> /// <param name="closeFileHandler">Callback for closing extracted file streams. This may be null, in which /// case the stream's <see cref="Stream.Close"/> method will be called.</param> /// <param name="openFileContext">User context object that will be passed to the /// <paramref name="openFileHandler"/> and <paramref name="closeFileHandler"/>.</param> /// <param name="filterFileHandler">Callback for filtering the list of extracted files. If null, /// all files will be extracted.</param> /// <param name="filterContext">User context object that will be passed to the /// <paramref name="filterFileHandler"/>.</param> /// <param name="statusCallback">Callback for reporting extraction status. This may be null /// if status is not desired.</param> /// <param name="statusContext">User context object passed to the <paramref name="statusCallback"/>.</param> /// <exception cref="CabinetExtractException">The stream is not a cabinet file or the cabinet file is corrupt.</exception> public static void Extract(Stream stream, CabinetExtractOpenFileHandler openFileHandler, CabinetExtractCloseFileHandler closeFileHandler, object openFileContext, CabinetFilterFileHandler filterFileHandler, object filterContext, CabinetStatusCallback statusCallback, object statusContext) #endif { if (stream == null) { throw new ArgumentNullException("stream"); } Cabinet.Extract(new CabinetOpenCabHandler(Cabinet.DefaultOpenCabHandler), new CabinetCloseCabHandler(Cabinet.DefaultCloseCabHandler), stream, false, openFileHandler, closeFileHandler, openFileContext, filterFileHandler, filterContext #if !CABMINIMAL , statusCallback, statusContext #endif // !CABMINIMAL ); }
/// <summary> /// Reads a single file from a cabinet or cabinet chain. /// </summary> /// <param name="openCabHandler">Callback for opening cabinet streams.</param> /// <param name="closeCabHandler">Callback for closing cabinet streams. This may be null, in which /// case the stream's <see cref="Stream.Close"/> method will be called.</param> /// <param name="openCabContext">User context object that will be passed to the /// <paramref name="openCabHandler"/> and <paramref name="closeCabHandler"/>.</param> /// <param name="autoChain">True to automatically process multiple cabinets in a chain. If false, the /// aggregate list of files may still be obtained by getting the file list from each cab individually.</param> /// <param name="name">Name of the file within the cabinet (not the external file path).</param> /// <returns>A stream for reading the extracted file, or null if the file does not exist in the cabinet.</returns> /// <exception cref="CabinetExtractException">The stream is not a cabinet file or the cabinet file is corrupt.</exception> /// <remarks>This method may fail if the file size is greater than available memory.</remarks> public static Stream Extract(CabinetOpenCabHandler openCabHandler, CabinetCloseCabHandler closeCabHandler, object openCabContext, bool autoChain, string name) { object[] openFileContext = new object[1]; Cabinet.Extract(openCabHandler, closeCabHandler, openCabContext, autoChain, new CabinetExtractOpenFileHandler(Cabinet.ExtractBytesOpenFileHandler), null, openFileContext, new CabinetFilterFileHandler(Cabinet.ExtractBytesFilterFileHandler), name #if !CABMINIMAL , null, null #endif // !CABMINIMAL ); MemoryStream extractStream = (MemoryStream)openFileContext[0]; if (extractStream != null) { extractStream.Position = 0; } return(extractStream); }
public void CanExtractSingleFileCabinet() { var cabinetPath = TestData.Get(@"TestData\test.cab"); using (var fs = new DisposableFileSystem()) { var extractFolder = fs.GetFolder(true); var cabinet = new Cabinet(cabinetPath); cabinet.Extract(extractFolder); var files = Directory.EnumerateFiles(extractFolder); var file = new FileInfo(files.Single()); CabInterop.DateTimeToCabDateAndTime(file.CreationTime, out var date, out var time); Assert.Equal("test.txt", file.Name); Assert.Equal(17, file.Length); Assert.Equal(19259, date); Assert.Equal(47731, time); } }
/// <summary> /// Gets the attached container from the exe and extracts its contents to the output directory. /// </summary> /// <param name="outputDirectory">Directory to write extracted files to.</param> /// <returns>True if successful, false otherwise</returns> public bool ExtractAttachedContainer(string outputDirectory, string tempDirectory) { // No attached container to extract if (this.AttachedContainerAddress == 0 || this.AttachedContainerSize == 0) { return(false); } if (this.invalidBundle) { return(false); } Directory.CreateDirectory(outputDirectory); string tempCabPath = Path.Combine(tempDirectory, "attached.cab"); this.binaryReader.BaseStream.Seek(this.AttachedContainerAddress, SeekOrigin.Begin); using (Stream tempCab = File.Open(tempCabPath, FileMode.Create, FileAccess.Write)) { BurnCommon.CopyStream(this.binaryReader.BaseStream, tempCab, (int)this.AttachedContainerSize); } var cabinet = new Cabinet(tempCabPath); cabinet.Extract(outputDirectory); foreach (DictionaryEntry entry in this.attachedContainerPayloadNames) { string sourcePath = Path.Combine(outputDirectory, (string)entry.Key); string destinationPath = Path.Combine(outputDirectory, (string)entry.Value); Directory.CreateDirectory(Path.GetDirectoryName(destinationPath)); File.Delete(destinationPath); File.Move(sourcePath, destinationPath); } return(true); }
public void Execute() { var databaseBasePath = Path.GetDirectoryName(this.InputFilePath); var cabinetFiles = new List <string>(); var embeddedCabinets = new SortedList(); // index all of the cabinet files if (OutputType.Module == this.Output.Type || this.TreatOutputAsModule) { embeddedCabinets.Add(0, "MergeModule.CABinet"); } else if (null != this.Output.Tables["Media"]) { foreach (MediaRow mediaRow in this.Output.Tables["Media"].Rows) { if (null != mediaRow.Cabinet) { if (OutputType.Product == this.Output.Type || (OutputType.Transform == this.Output.Type && RowOperation.Add == mediaRow.Operation)) { if (mediaRow.Cabinet.StartsWith("#", StringComparison.Ordinal)) { embeddedCabinets.Add(mediaRow.DiskId, mediaRow.Cabinet.Substring(1)); } else { cabinetFiles.Add(Path.Combine(databaseBasePath, mediaRow.Cabinet)); } } } } } // extract the embedded cabinet files from the database if (0 < embeddedCabinets.Count) { using (var streamsView = this.Database.OpenView("SELECT `Data` FROM `_Streams` WHERE `Name` = ?")) { foreach (int diskId in embeddedCabinets.Keys) { using (var record = new Record(1)) { record.SetString(1, (string)embeddedCabinets[diskId]); streamsView.Execute(record); } using (var record = streamsView.Fetch()) { if (null != record) { // since the cabinets are stored in case-sensitive streams inside the msi, but the file system is not (typically) case-sensitive, // embedded cabinets must be extracted to a canonical file name (like their diskid) to ensure extraction will always work var cabinetFile = Path.Combine(this.IntermediateFolder, String.Concat("Media", Path.DirectorySeparatorChar, diskId.ToString(CultureInfo.InvariantCulture), ".cab")); // ensure the parent directory exists Directory.CreateDirectory(Path.GetDirectoryName(cabinetFile)); using (var fs = File.Create(cabinetFile)) { int bytesRead; var buffer = new byte[512]; while (0 != (bytesRead = record.GetStream(1, buffer, buffer.Length))) { fs.Write(buffer, 0, bytesRead); } } cabinetFiles.Add(cabinetFile); } else { // TODO: warning about missing embedded cabinet } } } } } // extract the cabinet files if (0 < cabinetFiles.Count) { // ensure the directory exists or extraction will fail Directory.CreateDirectory(this.ExportBasePath); foreach (var cabinetFile in cabinetFiles) { try { var cabinet = new Cabinet(cabinetFile); this.ExtractedFiles = cabinet.Extract(this.ExportBasePath).ToArray(); } catch (FileNotFoundException) { throw new WixException(ErrorMessages.FileNotFound(new SourceLineNumber(this.InputFilePath), cabinetFile)); } } } else { this.ExtractedFiles = new string[0]; } }
/// <summary> /// Gets the UX container from the exe and extracts its contents to the output directory. /// </summary> /// <param name="outputDirectory">Directory to write extracted files to.</param> /// <returns>True if successful, false otherwise</returns> public bool ExtractUXContainer(string outputDirectory, string tempDirectory) { // No UX container to extract if (this.UXAddress == 0 || this.UXSize == 0) { return(false); } if (this.invalidBundle) { return(false); } Directory.CreateDirectory(outputDirectory); string tempCabPath = Path.Combine(tempDirectory, "ux.cab"); string manifestOriginalPath = Path.Combine(outputDirectory, "0"); string manifestPath = Path.Combine(outputDirectory, "manifest.xml"); this.binaryReader.BaseStream.Seek(this.UXAddress, SeekOrigin.Begin); using (Stream tempCab = File.Open(tempCabPath, FileMode.Create, FileAccess.Write)) { BurnCommon.CopyStream(this.binaryReader.BaseStream, tempCab, (int)this.UXSize); } var cabinet = new Cabinet(tempCabPath); cabinet.Extract(outputDirectory); Directory.CreateDirectory(Path.GetDirectoryName(manifestPath)); File.Delete(manifestPath); File.Move(manifestOriginalPath, manifestPath); XmlDocument document = new XmlDocument(); document.Load(manifestPath); XmlNamespaceManager namespaceManager = new XmlNamespaceManager(document.NameTable); namespaceManager.AddNamespace("burn", BurnCommon.BurnNamespace); XmlNodeList uxPayloads = document.SelectNodes("/burn:BurnManifest/burn:UX/burn:Payload", namespaceManager); XmlNodeList payloads = document.SelectNodes("/burn:BurnManifest/burn:Payload", namespaceManager); foreach (XmlNode uxPayload in uxPayloads) { XmlNode sourcePathNode = uxPayload.Attributes.GetNamedItem("SourcePath"); XmlNode filePathNode = uxPayload.Attributes.GetNamedItem("FilePath"); string sourcePath = Path.Combine(outputDirectory, sourcePathNode.Value); string destinationPath = Path.Combine(outputDirectory, filePathNode.Value); Directory.CreateDirectory(Path.GetDirectoryName(destinationPath)); File.Delete(destinationPath); File.Move(sourcePath, destinationPath); } foreach (XmlNode payload in payloads) { XmlNode sourcePathNode = payload.Attributes.GetNamedItem("SourcePath"); XmlNode filePathNode = payload.Attributes.GetNamedItem("FilePath"); XmlNode packagingNode = payload.Attributes.GetNamedItem("Packaging"); string sourcePath = sourcePathNode.Value; string destinationPath = filePathNode.Value; string packaging = packagingNode.Value; if (packaging.Equals("embedded", StringComparison.OrdinalIgnoreCase)) { this.attachedContainerPayloadNames.Add(new DictionaryEntry(sourcePath, destinationPath)); } } return(true); }