Ejemplo n.º 1
0
        private void DumpStorage(StorageInfo storageInfo, string storageName, XmlWriter writer)
        {
            writer.WriteStartElement("storage");
            writer.WriteAttributeString("name", storageName);

            StorageInfo[] subStorages = storageInfo.GetSubStorages();
            foreach (StorageInfo subStorage in subStorages)
            {
                DumpStorage(subStorage, subStorage.Name, writer);
            }

            StreamInfo[] streams = storageInfo.GetStreams();
            foreach (StreamInfo stream in streams)
            {
                string hexData = ConvertStreamBytesToHex(stream);
                writer.WriteStartElement("stream");
                using (var rawStream = new BinaryReader(stream.GetStream(FileMode.Open, FileAccess.Read)))
                {
                    var streamsBase = Path.Combine(BasePath, Path.GetFileName(_oleStorageFilePath.FullPathString) + "_streams");
                    FileSystem.CreateDirectory(streamsBase);
                    File.WriteAllBytes(Path.Combine(streamsBase, stream.Name).FullPathString, rawStream.ReadBytes((int)rawStream.BaseStream.Length));
                    writer.WriteAttributeString("name", stream.Name);
                    writer.WriteAttributeString("data", hexData);
                    writer.WriteEndElement();
                }
            }

            writer.WriteEndElement();
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Extracts cab files from the specified MSIDB and puts them in the specified outputdir.
        /// </summary>
        /// <param name="msidb"></param>
        /// <param name="outputDir"></param>
        /// <returns></returns>
        private static List <CabInfo> CabsFromMsiToDisk(Path msi, Database msidb, string outputDir)
        {
            const string query         = "SELECT * FROM `Media`";
            var          localCabFiles = new List <CabInfo>();

            using (View view = msidb.OpenExecuteView(query))
            {
                Record record = null;

                try
                {
                    while (view.Fetch(out record))
                    {
                        const int MsiInterop_Media_Cabinet = 4;
                        string    cabSourceName            = record[MsiInterop_Media_Cabinet];
                        if (string.IsNullOrEmpty(cabSourceName))
                        {
                            Debug.Print("Empty Cabinet value in Media table. This happens, but it's rare and it's weird!");//Debug.Fail("Couldn't find media CAB file inside the MSI (bad media table?).");
                            continue;
                        }
                        if (!string.IsNullOrEmpty(cabSourceName))
                        {
                            bool extract = false;
                            if (cabSourceName.StartsWith("#"))
                            {
                                extract       = true;
                                cabSourceName = cabSourceName.Substring(1);
                            }
                            Path localCabFile = Path.Combine(outputDir, cabSourceName);
                            if (extract)
                            {
                                // extract cabinet, then explode all of the files to a temp directory
                                ExtractCabFromPackage(localCabFile, cabSourceName, msidb, msi);
                            }
                            else
                            {
                                Path originalCabFile = Path.Combine(msi.Parent, cabSourceName);
                                FileSystem.Copy(originalCabFile, localCabFile);
                            }

                            /* http://code.google.com/p/lessmsi/issues/detail?id=1
                             * apparently in some cases a file spans multiple CABs (VBRuntime.msi) so due to that we have get all CAB files out of the MSI and then begin extraction. Then after we extract everything out of all CAbs we need to release the CAB extractors and delete temp files.
                             * Thanks to Christopher Hamburg for explaining this!
                             */
                            var c = new CabInfo(localCabFile.PathString, cabSourceName);
                            localCabFiles.Add(c);
                        }
                    }
                }
                finally
                {
                    if (record != null)
                    {
                        record.Close();
                    }
                }
            }
            return(localCabFiles);
        }
Ejemplo n.º 3
0
        public void Dump()
        {
            var dumpfileName = Path.Combine(BasePath, Path.GetFileName(_oleStorageFilePath.FullPathString) + "_streams.xml").FullPathString;

            using (var writer = XmlWriter.Create(dumpfileName, new XmlWriterSettings {
                Indent = true
            }))
            {
                DumpStorage(StorageRoot, "root", writer);
            }
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Extracts the compressed files from the specified MSI file to the specified output directory.
        /// If specified, the list of <paramref name="filesToExtract"/> objects are the only files extracted.
        /// </summary>
        /// <param name="msi">The MSI file to extract files from.</param>
        /// <param name="outputDir">The directory to extract the files into.</param>
        /// <param name="filesToExtract">The files to extract or null or empty to extract all files.</param>
        /// <param name="progressCallback">Will be called during during the operation with progress information, and upon completion. The argument will be of type <see cref="ExtractionProgress"/>.</param>
        public static void ExtractFiles(Path msi, string outputDir, MsiFile[] filesToExtract, AsyncCallback progressCallback)
        {
            if (msi.IsEmpty)
            {
                throw new ArgumentNullException("msi");
            }
            if (string.IsNullOrEmpty(outputDir))
            {
                throw new ArgumentNullException("outputDir");
            }

            int filesExtractedSoFar = 0;
            //Refrence on Embedding files: https://msdn.microsoft.com/en-us/library/aa369279.aspx
            ExtractionProgress progress = null;
            Database           msidb    = new Database(msi.PathString, DatabaseOpenMode.ReadOnly);

            try
            {
                if (filesToExtract == null || filesToExtract.Length < 1)
                {
                    filesToExtract = MsiFile.CreateMsiFilesFromMSI(msidb);
                }

                progress = new ExtractionProgress(progressCallback, filesToExtract.Length);

                if (!FileSystem.Exists(msi))
                {
                    Trace.WriteLine("File \'" + msi + "\' not found.");
                    progress.ReportProgress(ExtractionActivity.Complete, string.Empty, filesExtractedSoFar);
                    return;
                }

                progress.ReportProgress(ExtractionActivity.Initializing, string.Empty, filesExtractedSoFar);
                FileSystem.CreateDirectory(new Path(outputDir));

                //map short file names to the msi file entry
                var fileEntryMap = new Dictionary <string, MsiFile>(filesToExtract.Length, StringComparer.InvariantCulture);
                foreach (MsiFile fileEntry in filesToExtract)
                {
                    MsiFile existingFile = null;
                    if (fileEntryMap.TryGetValue(fileEntry.File, out existingFile))
                    {
                        //NOTE: This used to be triggered when we ignored case of file, but now we don't ignore case so this is unlikely to occur.
                        // Differing only by case is not compliant with the msi specification but some installers do it (e.g. python, see issue 28).
                        Debug.Print("!!Found duplicate file using key {0}. The existing key was {1}", fileEntry.File, existingFile.File);
                    }
                    else
                    {
                        fileEntryMap.Add(fileEntry.File, fileEntry);
                    }
                }

                Debug.Assert(fileEntryMap.Count == filesToExtract.Length, "Duplicate files must have caused some files to not be in the map.");

                progress.ReportProgress(ExtractionActivity.Uncompressing, string.Empty, filesExtractedSoFar);
                List <CabInfo> cabInfos = CabsFromMsiToDisk(msi, msidb, outputDir);

                try
                {
                    foreach (CabInfo cab in cabInfos)
                    {
                        foreach (CabFileInfo cabFile in cab.GetFiles())
                        {
                            var sourcePath = Path.Combine(cabFile.Path, cabFile.Name);
                            if (fileEntryMap.TryGetValue(sourcePath.PathString, out MsiFile msiFile))
                            {
                                Path destPath         = Path.Combine(GetTargetDirectory(outputDir, msiFile.Directory.FullPath), msiFile.LongFileName);
                                Path relativeDestPath = Path.Combine(msiFile.Directory.FullPath, msiFile.LongFileName);
                                progress.ReportProgress(ExtractionActivity.ExtractingFile, relativeDestPath.PathString, ++filesExtractedSoFar);
                                cab.UnpackFile(sourcePath.PathString, destPath.PathString);
                            }
                        }
                    }
                }
                finally
                {
                    foreach (CabInfo cab in cabInfos)
                    {
                        DeleteFileForcefully(new Path(cab.FullName));
                    }
                }
            }
            finally
            {
                if (msidb != null)
                {
                    msidb.Close();
                }
                if (progress != null)
                {
                    progress.ReportProgress(ExtractionActivity.Complete, "", filesExtractedSoFar);
                }
            }
        }