Пример #1
0
 /// <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));
 }
Пример #2
0
 /// <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();
                }
            }
        }
Пример #4
0
 /// <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);
     }
 }
Пример #5
0
        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));
                    }
                }
            }
        }
Пример #6
0
 /// <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
                     );
 }
Пример #7
0
 /// <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);
 }
Пример #8
0
        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);
            }
        }
Пример #9
0
        /// <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];
            }
        }
Пример #11
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);
        }