Example #1
0
        /// <summary>
        /// Loads a pdb from a path on disk.
        /// </summary>
        /// <param name="stream">Stream containing the pdb file.</param>
        /// <param name="uri">Uri for finding this stream.</param>
        /// <param name="suppressVersionCheck">Suppresses wix.dll version mismatch check.</param>
        /// <param name="suppressSchema">Suppress xml schema validation while loading.</param>
        /// <returns>Returns the loaded pdb.</returns>
        /// <remarks>This method will set the Path and SourcePath properties to the appropriate values on successful load.</remarks>
        internal static Pdb Load(Stream stream, Uri uri, bool suppressVersionCheck, bool suppressSchema)
        {
            XmlReader reader  = null;
            string    cabPath = null;

            // look for the Microsoft cabinet file header and save the cabinet data if found
            if ('M' == stream.ReadByte() && 'S' == stream.ReadByte() && 'C' == stream.ReadByte() && 'F' == stream.ReadByte())
            {
                long   cabFileSize  = 0;
                byte[] offsetBuffer = new byte[4];
                using (TempFileCollection tempFileCollection = new TempFileCollection())
                {
                    cabPath = tempFileCollection.AddExtension("cab", true);
                }

                // skip the header checksum
                stream.Seek(4, SeekOrigin.Current);

                // get the cabinet file size
                stream.Read(offsetBuffer, 0, 4);
                cabFileSize = BitConverter.ToInt32(offsetBuffer, 0);

                stream.Seek(0, SeekOrigin.Begin);

                // Create the cab file from stream
                using (FileStream fs = File.Create(cabPath))
                {
                    for (int i = 0; i < cabFileSize; i++)
                    {
                        fs.WriteByte((byte)stream.ReadByte());
                    }
                }
            }
            else // plain xml file - start reading xml at the beginning of the stream
            {
                stream.Seek(0, SeekOrigin.Begin);
            }

            // read the xml
            try
            {
                reader = new XmlTextReader(uri.AbsoluteUri, stream);

                if (!suppressSchema)
                {
                    reader = new XmlValidatingReader(reader);
                    ((XmlValidatingReader)reader).Schemas.Add(GetSchemas());
                }

                reader.MoveToContent();

                if ("wixPdb" != reader.LocalName)
                {
                    throw new WixNotOutputException(WixErrors.InvalidDocumentElement(SourceLineNumberCollection.FromUri(reader.BaseURI), reader.Name, "pdb", "wixPdb"));
                }

                Pdb pdb = Parse(reader, suppressVersionCheck);

                if (null != cabPath)
                {
                    if (pdb.Output.TempFiles == null)
                    {
                        pdb.Output.TempFiles = new TempFileCollection();
                    }

                    pdb.Output.TempFiles.AddFile(cabPath, false);
                }

                return(pdb);
            }
            catch (XmlException xe)
            {
                throw new WixException(WixErrors.InvalidXml(SourceLineNumberCollection.FromUri(reader.BaseURI), "output", xe.Message));
            }
            catch (XmlSchemaException xse)
            {
                throw new WixException(WixErrors.SchemaValidationFailed(SourceLineNumberCollection.FromUri(reader.BaseURI), xse.Message, xse.LineNumber, xse.LinePosition));
            }
            finally
            {
                if (null != reader)
                {
                    reader.Close();
                }
            }
        }
Example #2
0
        /// <summary>
        /// Processes an XmlReader and builds up the pdb object.
        /// </summary>
        /// <param name="reader">Reader to get data from.</param>
        /// <param name="suppressVersionCheck">Suppresses wix.dll version mismatch check.</param>
        /// <returns>The Pdb represented by the Xml.</returns>
        internal static Pdb Parse(XmlReader reader, bool suppressVersionCheck)
        {
            Debug.Assert("wixPdb" == reader.LocalName);

            bool    empty   = reader.IsEmptyElement;
            Pdb     pdb     = new Pdb(SourceLineNumberCollection.FromUri(reader.BaseURI));
            Version version = null;

            while (reader.MoveToNextAttribute())
            {
                switch (reader.LocalName)
                {
                case "version":
                    version = new Version(reader.Value);
                    break;

                default:
                    if (!reader.NamespaceURI.StartsWith("http://www.w3.org/", StringComparison.Ordinal))
                    {
                        throw new WixException(WixErrors.UnexpectedAttribute(SourceLineNumberCollection.FromUri(reader.BaseURI), "wixPdb", reader.Name));
                    }
                    break;
                }
            }

            if (null != version)
            {
                if (0 != currentVersion.CompareTo(version))
                {
                    throw new WixException(WixErrors.VersionMismatch(SourceLineNumberCollection.FromUri(reader.BaseURI), "wixPdb", version.ToString(), currentVersion.ToString()));
                }
            }

            // loop through the rest of the pdb building up the Output object
            if (!empty)
            {
                bool done = false;

                // loop through all the fields in a row
                while (!done && reader.Read())
                {
                    switch (reader.NodeType)
                    {
                    case XmlNodeType.Element:
                        switch (reader.LocalName)
                        {
                        case "wixOutput":
                            pdb.output = Output.Parse(reader, suppressVersionCheck);
                            break;

                        default:
                            throw new WixException(WixErrors.UnexpectedElement(SourceLineNumberCollection.FromUri(reader.BaseURI), "wixPdb", reader.Name));
                        }
                        break;

                    case XmlNodeType.EndElement:
                        done = true;
                        break;
                    }
                }

                if (!done)
                {
                    throw new WixException(WixErrors.ExpectedEndElement(SourceLineNumberCollection.FromUri(reader.BaseURI), "wixOutput"));
                }
            }

            return(pdb);
        }
        private static Wix.Table GetBundlesFromWixPDB(Microsoft.Tools.WindowsInstallerXml.Pdb pdb)
        {
            var wixbundle = pdb.Output.Tables[WIXBUNDLE];  //Id: 32 in pdb.Output.Rows

            return(wixbundle);
        }
Example #4
0
File: Binder.cs Project: zooba/wix3
        private bool BindDatabase(Output output, string databaseFile)
        {
            foreach (BinderExtension extension in this.extensions)
            {
                extension.DatabaseInitialize(output);
            }

            bool compressed = false;
            FileRowCollection fileRows = new FileRowCollection(OutputType.Patch == output.Type);
            bool longNames = false;
            MediaRowCollection mediaRows = new MediaRowCollection();
            Hashtable suppressModularizationIdentifiers = null;
            StringCollection suppressedTableNames = new StringCollection();
            Table propertyTable = output.Tables["Property"];

            this.WriteBuildInfoTable(output, databaseFile);

            // gather all the wix variables
            Table wixVariableTable = output.Tables["WixVariable"];
            if (null != wixVariableTable)
            {
                foreach (WixVariableRow wixVariableRow in wixVariableTable.Rows)
                {
                    this.WixVariableResolver.AddVariable(wixVariableRow);
                }
            }

            // gather all the suppress modularization identifiers
            Table wixSuppressModularizationTable = output.Tables["WixSuppressModularization"];
            if (null != wixSuppressModularizationTable)
            {
                suppressModularizationIdentifiers = new Hashtable(wixSuppressModularizationTable.Rows.Count);

                foreach (Row row in wixSuppressModularizationTable.Rows)
                {
                    suppressModularizationIdentifiers[row[0]] = null;
                }
            }

            // localize fields, resolve wix variables, and resolve file paths
            Hashtable cabinets = new Hashtable();
            ArrayList delayedFields = new ArrayList();
            this.ResolveFields(output.Tables, cabinets, delayedFields);

            // if there are any fields to resolve later, create the cache to populate during bind
            IDictionary<string, string> variableCache = null;
            if (0 < delayedFields.Count)
            {
                variableCache = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
            }

            this.LocalizeUI(output.Tables);

            // process the summary information table before the other tables
            string modularizationGuid = this.BindDatabaseSummaryInfo(output, out longNames, out compressed);

            // stop processing if an error previously occurred
            if (this.core.EncounteredError)
            {
                return false;
            }

            // modularize identifiers and add tables with real streams to the import tables
            if (OutputType.Module == output.Type)
            {
                foreach (Table table in output.Tables)
                {
                    table.Modularize(modularizationGuid, suppressModularizationIdentifiers);
                }

                // Reset the special property lists after modularization. The linker creates these properties before modularization
                // so we have to reconstruct them for merge modules after modularization in the binder.
                Table wixPropertyTable = output.Tables["WixProperty"];
                if (null != wixPropertyTable)
                {
                    // Create lists of the properties that contribute to the special lists of properties.
                    SortedList adminProperties = new SortedList();
                    SortedList secureProperties = new SortedList();
                    SortedList hiddenProperties = new SortedList();

                    foreach (WixPropertyRow wixPropertyRow in wixPropertyTable.Rows)
                    {
                        if (wixPropertyRow.Admin)
                        {
                            adminProperties[wixPropertyRow.Id] = null;
                        }

                        if (wixPropertyRow.Hidden)
                        {
                            hiddenProperties[wixPropertyRow.Id] = null;
                        }

                        if (wixPropertyRow.Secure)
                        {
                            secureProperties[wixPropertyRow.Id] = null;
                        }
                    }

                    if (0 < adminProperties.Count || 0 < hiddenProperties.Count || 0 < secureProperties.Count)
                    {
                        Table table = output.Tables["Property"];
                        foreach (Row propertyRow in table.Rows)
                        {
                            if ("AdminProperties" == (string)propertyRow[0])
                            {
                                propertyRow[1] = GetPropertyListString(adminProperties);
                            }

                            if ("MsiHiddenProperties" == (string)propertyRow[0])
                            {
                                propertyRow[1] = GetPropertyListString(hiddenProperties);
                            }

                            if ("SecureCustomProperties" == (string)propertyRow[0])
                            {
                                propertyRow[1] = GetPropertyListString(secureProperties);
                            }
                        }
                    }
                }
            }

            // merge unreal table data into the real tables
            // this must occur after all variables and source paths have been resolved
            this.MergeUnrealTables(output.Tables);

            if (this.core.EncounteredError)
            {
                return false;
            }

            if (OutputType.Patch == output.Type)
            {
                foreach (SubStorage substorage in output.SubStorages)
                {
                    Output transform = (Output)substorage.Data;
                    this.ResolveFields(transform.Tables, cabinets, null);
                    this.MergeUnrealTables(transform.Tables);
                }
            }

            // stop processing if an error previously occurred
            if (this.core.EncounteredError)
            {
                return false;
            }

            // index the File table for quicker access later
            // this must occur after the unreal data has been merged in
            Table fileTable = output.Tables["File"];
            if (null != fileTable)
            {
                fileRows.AddRange(fileTable.Rows);
            }

            // stop processing if an error previously occurred
            if (this.core.EncounteredError)
            {
                return false;
            }

            // add binder variables for all properties
            propertyTable = output.Tables["Property"];
            if (null != propertyTable)
            {
                foreach (Row propertyRow in propertyTable.Rows)
                {
                    string property = propertyRow[0].ToString();

                    // set the ProductCode if its generated
                    if (OutputType.Product == output.Type && "ProductCode" == property && "*" == propertyRow[1].ToString())
                    {
                        propertyRow[1] = Common.GenerateGuid();

                        // Update the target ProductCode in any instance transforms
                        foreach (SubStorage subStorage in output.SubStorages)
                        {
                            Output subStorageOutput = (Output)subStorage.Data;
                            if (OutputType.Transform != subStorageOutput.Type)
                            {
                                continue;
                            }

                            Table instanceSummaryInformationTable = subStorageOutput.Tables["_SummaryInformation"];
                            foreach (Row row in instanceSummaryInformationTable.Rows)
                            {
                                if ((int)SummaryInformation.Transform.ProductCodes == (int)row[0])
                                {
                                    row[1] = ((string)row[1]).Replace("*", (string)propertyRow[1]);
                                    break;
                                }
                            }
                        }
                    }

                    // add the property name and value to the variableCache
                    if (0 != delayedFields.Count)
                    {
                        string key = String.Concat("property.", Demodularize(output, modularizationGuid, property));
                        variableCache[key] = (string)propertyRow[1];
                    }
                }
            }

            // extract files that come from cabinet files (this does not extract files from merge modules)
            this.ExtractCabinets(cabinets);

            // retrieve files and their information from merge modules
            if (OutputType.Product == output.Type)
            {
                this.ProcessMergeModules(output, fileRows);
            }
            else if (OutputType.Patch == output.Type)
            {
                // merge transform data into the output object
                this.CopyTransformData(output, fileRows);
            }

            // stop processing if an error previously occurred
            if (this.core.EncounteredError)
            {
                return false;
            }

            // assign files to media
            AutoMediaAssigner autoMediaAssigner = new AutoMediaAssigner(output, this.core, compressed);
            autoMediaAssigner.AssignFiles(fileRows);

            // update file version, hash, assembly, etc.. information
            this.core.OnMessage(WixVerboses.UpdatingFileInformation());
            Hashtable indexedFileRows = this.UpdateFileInformation(output, fileRows, autoMediaAssigner.MediaRows, variableCache, modularizationGuid);

            // set generated component guids
            this.SetComponentGuids(output);

            // With the Component Guids set now we can create instance transforms.
            this.CreateInstanceTransforms(output);

            this.ValidateComponentGuids(output);

            this.UpdateControlText(output);

            if (0 < delayedFields.Count)
            {
                this.ResolveDelayedFields(output, delayedFields, variableCache, modularizationGuid);
            }

            // stop processing if an error previously occurred
            if (this.core.EncounteredError)
            {
                return false;
            }

            // Extended binder extensions can be called now that fields are resolved.
            foreach (BinderExtension extension in this.extensions)
            {
                BinderExtensionEx extensionEx = extension as BinderExtensionEx;
                if (null != extensionEx)
                {
                    output.EnsureTable(this.core.TableDefinitions["WixBindUpdatedFiles"]);
                    extensionEx.DatabaseAfterResolvedFields(output);
                }
            }

            Table updatedFiles = output.Tables["WixBindUpdatedFiles"];
            if (null != updatedFiles)
            {
                foreach (Row updatedFile in updatedFiles.Rows)
                {
                    FileRow updatedFileRow = (FileRow)indexedFileRows[updatedFile[0]];
                    this.UpdateFileRow(output, null, modularizationGuid, indexedFileRows, updatedFileRow, true);
                }
            }

            // stop processing if an error previously occurred
            if (this.core.EncounteredError)
            {
                return false;
            }

            // create cabinet files and process uncompressed files
            string layoutDirectory = Path.GetDirectoryName(databaseFile);
            FileRowCollection uncompressedFileRows = null;
            if (!this.suppressLayout || OutputType.Module == output.Type)
            {
                this.core.OnMessage(WixVerboses.CreatingCabinetFiles());
                uncompressedFileRows = this.CreateCabinetFiles(output, fileRows, this.fileTransfers, autoMediaAssigner.MediaRows, layoutDirectory, compressed, autoMediaAssigner);
            }

            if (OutputType.Patch == output.Type)
            {
                // copy output data back into the transforms
                this.CopyTransformData(output, null);
            }

            // stop processing if an error previously occurred
            if (this.core.EncounteredError)
            {
                return false;
            }

            // add back suppressed tables which must be present prior to merging in modules
            if (OutputType.Product == output.Type)
            {
                Table wixMergeTable = output.Tables["WixMerge"];

                if (null != wixMergeTable && 0 < wixMergeTable.Rows.Count)
                {
                    foreach (SequenceTable sequence in Enum.GetValues(typeof(SequenceTable)))
                    {
                        string sequenceTableName = sequence.ToString();
                        Table sequenceTable = output.Tables[sequenceTableName];

                        if (null == sequenceTable)
                        {
                            sequenceTable = output.EnsureTable(this.core.TableDefinitions[sequenceTableName]);
                        }

                        if (0 == sequenceTable.Rows.Count)
                        {
                            suppressedTableNames.Add(sequenceTableName);
                        }
                    }
                }
            }

            foreach (BinderExtension extension in this.extensions)
            {
                extension.DatabaseFinalize(output);
            }

            // generate database file
            this.core.OnMessage(WixVerboses.GeneratingDatabase());
            string tempDatabaseFile = Path.Combine(this.TempFilesLocation, Path.GetFileName(databaseFile));
            this.GenerateDatabase(output, tempDatabaseFile, false, false);

            FileTransfer transfer;
            if (FileTransfer.TryCreate(tempDatabaseFile, databaseFile, true, output.Type.ToString(), null, out transfer)) // note where this database needs to move in the future
            {
                transfer.Built = true;
                this.fileTransfers.Add(transfer);
            }

            // stop processing if an error previously occurred
            if (this.core.EncounteredError)
            {
                return false;
            }

            // Output the output to a file
            if (null != this.pdbFile)
            {
                Pdb pdb = new Pdb(null);
                pdb.Output = output;
                pdb.Save(this.pdbFile, null, this.WixVariableResolver, this.TempFilesLocation);
            }

            // merge modules
            if (OutputType.Product == output.Type)
            {
                this.core.OnMessage(WixVerboses.MergingModules());
                this.MergeModules(tempDatabaseFile, output, fileRows, suppressedTableNames);

                // stop processing if an error previously occurred
                if (this.core.EncounteredError)
                {
                    return false;
                }
            }

            // inspect the MSI prior to running ICEs
            InspectorCore inspectorCore = new InspectorCore(this.MessageHandler);
            foreach (InspectorExtension inspectorExtension in this.inspectorExtensions)
            {
                inspectorExtension.Core = inspectorCore;
                inspectorExtension.InspectDatabase(tempDatabaseFile, output);

                // reset
                inspectorExtension.Core = null;
            }

            if (inspectorCore.EncounteredError)
            {
                return false;
            }

            // validate the output if there is an MSI validator
            if (null != this.validator)
            {
                Stopwatch stopwatch = Stopwatch.StartNew();

                // set the output file for source line information
                this.validator.Output = output;

                this.core.OnMessage(WixVerboses.ValidatingDatabase());
                this.core.EncounteredError = !this.validator.Validate(tempDatabaseFile);

                stopwatch.Stop();
                this.core.OnMessage(WixVerboses.ValidatedDatabase(stopwatch.ElapsedMilliseconds));

                // stop processing if an error previously occurred
                if (this.core.EncounteredError)
                {
                    return false;
                }
            }

            // process uncompressed files
            if (!this.suppressLayout)
            {
                this.ProcessUncompressedFiles(tempDatabaseFile, uncompressedFileRows, this.fileTransfers, autoMediaAssigner.MediaRows, layoutDirectory, compressed, longNames);
            }

            // layout media
            try
            {
                this.core.OnMessage(WixVerboses.LayingOutMedia());
                this.LayoutMedia(this.fileTransfers, this.suppressAclReset);
            }
            finally
            {
                if (!String.IsNullOrEmpty(this.contentsFile))
                {
                    this.CreateContentsFile(this.contentsFile, fileRows);
                }

                if (!String.IsNullOrEmpty(this.outputsFile))
                {
                    this.CreateOutputsFile(this.outputsFile, this.fileTransfers, this.pdbFile);
                }

                if (!String.IsNullOrEmpty(this.builtOutputsFile))
                {
                    this.CreateBuiltOutputsFile(this.builtOutputsFile, this.fileTransfers, this.pdbFile);
                }
            }

            return !this.core.EncounteredError;
        }
Example #5
0
File: Binder.cs Project: zooba/wix3
        /// <summary>
        /// Binds a bundle.
        /// </summary>
        /// <param name="bundle">The bundle to bind.</param>
        /// <param name="bundleFile">The bundle to create.</param>
        /// <returns>true if binding completed successfully; false otherwise</returns>
        private bool BindBundle(Output bundle, string bundleFile)
        {
            // First look for data we expect to find... Chain, WixGroups, etc.
            Table chainPackageTable = bundle.Tables["ChainPackage"];
            if (null == chainPackageTable || 0 == chainPackageTable.Rows.Count)
            {
                // We shouldn't really get past the linker phase if there are
                // no group items... that means that there's no UX, no Chain,
                // *and* no Containers!
                throw new WixException(WixErrors.MissingBundleInformation("ChainPackage"));
            }

            Table wixGroupTable = bundle.Tables["WixGroup"];
            if (null == wixGroupTable || 0 == wixGroupTable.Rows.Count)
            {
                // We shouldn't really get past the linker phase if there are
                // no group items... that means that there's no UX, no Chain,
                // *and* no Containers!
                throw new WixException(WixErrors.MissingBundleInformation("WixGroup"));
            }

            // Ensure there is one and only one row in the WixBundle table.
            // The compiler and linker behavior should have colluded to get
            // this behavior.
            Table bundleTable = bundle.Tables["WixBundle"];
            if (null == bundleTable || 1 != bundleTable.Rows.Count)
            {
                throw new WixException(WixErrors.MissingBundleInformation("WixBundle"));
            }

            // Ensure there is one and only one row in the WixBootstrapperApplication table.
            // The compiler and linker behavior should have colluded to get
            // this behavior.
            Table baTable = bundle.Tables["WixBootstrapperApplication"];
            if (null == baTable || 1 != baTable.Rows.Count)
            {
                throw new WixException(WixErrors.MissingBundleInformation("WixBootstrapperApplication"));
            }

            // Ensure there is one and only one row in the WixChain table.
            // The compiler and linker behavior should have colluded to get
            // this behavior.
            Table chainTable = bundle.Tables["WixChain"];
            if (null == chainTable || 1 != chainTable.Rows.Count)
            {
                throw new WixException(WixErrors.MissingBundleInformation("WixChain"));
            }

            foreach (BinderExtension extension in this.extensions)
            {
                extension.BundleInitialize(bundle);
            }

            if (this.core.EncounteredError)
            {
                return false;
            }

            this.WriteBuildInfoTable(bundle, bundleFile);

            // gather all the wix variables
            Table wixVariableTable = bundle.Tables["WixVariable"];
            if (null != wixVariableTable)
            {
                foreach (WixVariableRow wixVariableRow in wixVariableTable.Rows)
                {
                    this.WixVariableResolver.AddVariable(wixVariableRow);
                }
            }

            Hashtable cabinets = new Hashtable();
            ArrayList delayedFields = new ArrayList();

            // localize fields, resolve wix variables, and resolve file paths
            this.ResolveFields(bundle.Tables, cabinets, delayedFields);

            // if there are any fields to resolve later, create the cache to populate during bind
            IDictionary<string, string> variableCache = null;
            if (0 < delayedFields.Count)
            {
                variableCache = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
            }

            if (this.core.EncounteredError)
            {
                return false;
            }

            Table relatedBundleTable = bundle.Tables["RelatedBundle"];
            List<RelatedBundleInfo> allRelatedBundles = new List<RelatedBundleInfo>();
            if (null != relatedBundleTable && 0 < relatedBundleTable.Rows.Count)
            {
                Dictionary<string, bool> deduplicatedRelatedBundles = new Dictionary<string, bool>();
                foreach (Row row in relatedBundleTable.Rows)
                {
                    string id = (string)row[0];
                    if (!deduplicatedRelatedBundles.ContainsKey(id))
                    {
                        deduplicatedRelatedBundles[id] = true;
                        allRelatedBundles.Add(new RelatedBundleInfo(row));
                    }
                }
            }

            // Ensure that the bundle has our well-known persisted values.
            Table variableTable = bundle.EnsureTable(this.core.TableDefinitions["Variable"]);
            VariableRow bundleNameWellKnownVariable = (VariableRow)variableTable.CreateRow(null);
            bundleNameWellKnownVariable.Id = Binder.BURN_BUNDLE_NAME;
            bundleNameWellKnownVariable.Hidden = false;
            bundleNameWellKnownVariable.Persisted = true;

            VariableRow bundleOriginalSourceWellKnownVariable = (VariableRow)variableTable.CreateRow(null);
            bundleOriginalSourceWellKnownVariable.Id = Binder.BURN_BUNDLE_ORIGINAL_SOURCE;
            bundleOriginalSourceWellKnownVariable.Hidden = false;
            bundleOriginalSourceWellKnownVariable.Persisted = true;

            VariableRow bundleOriginalSourceFolderWellKnownVariable = (VariableRow)variableTable.CreateRow(null);
            bundleOriginalSourceFolderWellKnownVariable.Id = Binder.BURN_BUNDLE_ORIGINAL_SOURCE_FOLDER;
            bundleOriginalSourceFolderWellKnownVariable.Hidden = false;
            bundleOriginalSourceFolderWellKnownVariable.Persisted = true;

            VariableRow bundleLastUsedSourceWellKnownVariable = (VariableRow)variableTable.CreateRow(null);
            bundleLastUsedSourceWellKnownVariable.Id = Binder.BURN_BUNDLE_LAST_USED_SOURCE;
            bundleLastUsedSourceWellKnownVariable.Hidden = false;
            bundleLastUsedSourceWellKnownVariable.Persisted = true;

            // To make lookups easier, we load the variable table bottom-up, so
            // that we can index by ID.
            List<VariableInfo> allVariables = new List<VariableInfo>(variableTable.Rows.Count);
            foreach (VariableRow variableRow in variableTable.Rows)
            {
                allVariables.Add(new VariableInfo(variableRow));
            }

            // TODO: Although the WixSearch tables are defined in the Util extension,
            // the Bundle Binder has to know all about them. We hope to revisit all
            // of this in the 4.0 timeframe.
            Dictionary<string, WixSearchInfo> allSearches = new Dictionary<string, WixSearchInfo>();
            Table wixFileSearchTable = bundle.Tables["WixFileSearch"];
            if (null != wixFileSearchTable && 0 < wixFileSearchTable.Rows.Count)
            {
                foreach (Row row in wixFileSearchTable.Rows)
                {
                    WixFileSearchInfo fileSearchInfo = new WixFileSearchInfo(row);
                    allSearches.Add(fileSearchInfo.Id, fileSearchInfo);
                }
            }

            Table wixRegistrySearchTable = bundle.Tables["WixRegistrySearch"];
            if (null != wixRegistrySearchTable && 0 < wixRegistrySearchTable.Rows.Count)
            {
                foreach (Row row in wixRegistrySearchTable.Rows)
                {
                    WixRegistrySearchInfo registrySearchInfo = new WixRegistrySearchInfo(row);
                    allSearches.Add(registrySearchInfo.Id, registrySearchInfo);
                }
            }

            Table wixComponentSearchTable = bundle.Tables["WixComponentSearch"];
            if (null != wixComponentSearchTable && 0 < wixComponentSearchTable.Rows.Count)
            {
                foreach (Row row in wixComponentSearchTable.Rows)
                {
                    WixComponentSearchInfo componentSearchInfo = new WixComponentSearchInfo(row);
                    allSearches.Add(componentSearchInfo.Id, componentSearchInfo);
                }
            }

            Table wixProductSearchTable = bundle.Tables["WixProductSearch"];
            if (null != wixProductSearchTable && 0 < wixProductSearchTable.Rows.Count)
            {
                foreach (Row row in wixProductSearchTable.Rows)
                {
                    WixProductSearchInfo productSearchInfo = new WixProductSearchInfo(row);
                    allSearches.Add(productSearchInfo.Id, productSearchInfo);
                }
            }

            // Merge in the variable/condition info and get the canonical ordering for
            // the searches.
            List<WixSearchInfo> orderedSearches = new List<WixSearchInfo>();
            Table wixSearchTable = bundle.Tables["WixSearch"];
            if (null != wixSearchTable && 0 < wixSearchTable.Rows.Count)
            {
                orderedSearches.Capacity = wixSearchTable.Rows.Count;
                foreach (Row row in wixSearchTable.Rows)
                {
                    WixSearchInfo searchInfo = allSearches[(string)row[0]];
                    searchInfo.AddWixSearchRowInfo(row);
                    orderedSearches.Add(searchInfo);
                }
            }

            // extract files that come from cabinet files (this does not extract files from merge modules)
            this.ExtractCabinets(cabinets);

            WixBundleRow bundleInfo = (WixBundleRow)bundleTable.Rows[0];
            bundleInfo.PerMachine = true; // default to per-machine but the first-per user package would flip it.

            // Get update if specified.
            Table bundleUpdateTable = bundle.Tables["WixBundleUpdate"];
            WixBundleUpdateRow bundleUpdateRow = null;
            if (null != bundleUpdateTable)
            {
                bundleUpdateRow = (WixBundleUpdateRow)bundleUpdateTable.Rows[0];
            }

            // Get update registration if specified.
            Table updateRegistrationTable = bundle.Tables["WixUpdateRegistration"];
            WixUpdateRegistrationRow updateRegistrationInfo = null;
            if (null != updateRegistrationTable)
            {
                updateRegistrationInfo = (WixUpdateRegistrationRow)updateRegistrationTable.Rows[0];
            }

            // Get the explicit payloads.
            Table payloadTable = bundle.Tables["Payload"];
            Dictionary<string, PayloadInfoRow> allPayloads = new Dictionary<string, PayloadInfoRow>(payloadTable.Rows.Count);

            Table payloadInfoTable = bundle.EnsureTable(core.TableDefinitions["PayloadInfo"]);
            foreach (PayloadInfoRow row in payloadInfoTable.Rows)
            {
                allPayloads.Add(row.Id, row);
            }

            RowDictionary<Row> payloadDisplayInformationRows = new RowDictionary<Row>(bundle.Tables["PayloadDisplayInformation"]);
            foreach (Row row in payloadTable.Rows)
            {
                string id = (string)row[0];

                PayloadInfoRow payloadInfo = null;

                if (allPayloads.ContainsKey(id))
                {
                    payloadInfo = allPayloads[id];
                }
                else
                {
                    allPayloads.Add(id, payloadInfo = (PayloadInfoRow)payloadInfoTable.CreateRow(row.SourceLineNumbers));
                }

                payloadInfo.FillFromPayloadRow(bundle, row);

                // Check if there is an override row for the display name or description.
                Row payloadDisplayInformationRow;
                if (payloadDisplayInformationRows.TryGet(id, out payloadDisplayInformationRow))
                {
                    if (!String.IsNullOrEmpty(payloadDisplayInformationRow[1] as string))
                    {
                        payloadInfo.ProductName = (string)payloadDisplayInformationRow[1];
                    }

                    if (!String.IsNullOrEmpty(payloadDisplayInformationRow[2] as string))
                    {
                        payloadInfo.Description = (string)payloadDisplayInformationRow[2];
                    }
                }

                if (payloadInfo.Packaging == PackagingType.Unknown)
                {
                    payloadInfo.Packaging = bundleInfo.DefaultPackagingType;
                }
            }

            Dictionary<string, ContainerInfo> containers = new Dictionary<string, ContainerInfo>();
            Dictionary<string, bool> payloadsAddedToContainers = new Dictionary<string, bool>();

            // Create the list of containers.
            Table containerTable = bundle.Tables["Container"];
            if (null != containerTable)
            {
                foreach (Row row in containerTable.Rows)
                {
                    ContainerInfo container = new ContainerInfo(row, this.FileManager);
                    containers.Add(container.Id, container);
                }
            }

            // Create the default attached container for payloads that need to be attached but don't have an explicit container.
            ContainerInfo defaultAttachedContainer = new ContainerInfo("WixAttachedContainer", "bundle-attached.cab", "attached", null, this.FileManager);
            containers.Add(defaultAttachedContainer.Id, defaultAttachedContainer);

            Row baRow = baTable.Rows[0];
            string baPayloadId = (string)baRow[0];

            // Create lists of which payloads go in each container or are layout only.
            foreach (Row row in wixGroupTable.Rows)
            {
                string rowParentName = (string)row[0];
                string rowParentType = (string)row[1];
                string rowChildName = (string)row[2];
                string rowChildType = (string)row[3];

                if (Enum.GetName(typeof(ComplexReferenceChildType), ComplexReferenceChildType.Payload) == rowChildType)
                {
                    PayloadInfoRow payload = allPayloads[rowChildName];

                    if (Enum.GetName(typeof(ComplexReferenceParentType), ComplexReferenceParentType.Container) == rowParentType)
                    {
                        ContainerInfo container = containers[rowParentName];

                        // Make sure the BA DLL is the first payload.
                        if (payload.Id.Equals(baPayloadId))
                        {
                            container.Payloads.Insert(0, payload);
                        }
                        else
                        {
                            container.Payloads.Add(payload);
                        }

                        payload.Container = container.Id;
                        payloadsAddedToContainers.Add(rowChildName, false);
                    }
                    else if (Enum.GetName(typeof(ComplexReferenceParentType), ComplexReferenceParentType.Layout) == rowParentType)
                    {
                        payload.LayoutOnly = true;
                    }
                }
            }

            ContainerInfo burnUXContainer;
            containers.TryGetValue(Compiler.BurnUXContainerId, out burnUXContainer);
            List<PayloadInfoRow> uxPayloads = null == burnUXContainer ? null : burnUXContainer.Payloads;

            // If we didn't get any UX payloads, it's an error!
            if (null == uxPayloads || 0 == uxPayloads.Count)
            {
                throw new WixException(WixErrors.MissingBundleInformation("BootstrapperApplication"));
            }

            // Get the catalog information
            Dictionary<string, CatalogInfo> catalogs = new Dictionary<string, CatalogInfo>();
            Table catalogTable = bundle.Tables["WixCatalog"];
            if (null != catalogTable)
            {
                foreach (WixCatalogRow catalogRow in catalogTable.Rows)
                {
                    // Each catalog is also a payload
                    string payloadId = Common.GenerateIdentifier("pay", true, catalogRow.SourceFile);
                    string catalogFile = this.FileManager.ResolveFile(catalogRow.SourceFile, "Catalog", catalogRow.SourceLineNumbers, BindStage.Normal);
                    PayloadInfoRow payloadInfo = PayloadInfoRow.Create(catalogRow.SourceLineNumbers, bundle, payloadId, Path.GetFileName(catalogFile), catalogFile, true, false, null, burnUXContainer.Id, PackagingType.Embedded);

                    // Add the payload to the UX container
                    allPayloads.Add(payloadInfo.Id, payloadInfo);
                    burnUXContainer.Payloads.Add(payloadInfo);
                    payloadsAddedToContainers.Add(payloadInfo.Id, true);

                    // Create the catalog info
                    CatalogInfo catalog = new CatalogInfo(catalogRow, payloadId);
                    catalogs.Add(catalog.Id, catalog);
                }
            }

            // Get the chain packages, this may add more payloads.
            Dictionary<string, ChainPackageInfo> allPackages = new Dictionary<string, ChainPackageInfo>();
            Dictionary<string, RollbackBoundaryInfo> allBoundaries = new Dictionary<string, RollbackBoundaryInfo>();
            foreach (Row row in chainPackageTable.Rows)
            {
                Compiler.ChainPackageType type = (Compiler.ChainPackageType)Enum.Parse(typeof(Compiler.ChainPackageType), row[1].ToString(), true);
                if (Compiler.ChainPackageType.RollbackBoundary == type)
                {
                    RollbackBoundaryInfo rollbackBoundary = new RollbackBoundaryInfo(row);
                    allBoundaries.Add(rollbackBoundary.Id, rollbackBoundary);
                }
                else // package
                {
                    Table chainPackageInfoTable = bundle.EnsureTable(this.core.TableDefinitions["ChainPackageInfo"]);

                    ChainPackageInfo packageInfo = new ChainPackageInfo(row, wixGroupTable, allPayloads, containers, this.FileManager, this.core, bundle);
                    allPackages.Add(packageInfo.Id, packageInfo);

                    chainPackageInfoTable.Rows.Add(packageInfo);

                    // Add package properties to resolve fields later.
                    if (null != variableCache)
                    {
                        Binder.PopulatePackageVariableCache(packageInfo, variableCache);
                    }
                }
            }

            // Determine patches to automatically slipstream.
            this.AutomaticallySlipstreamPatches(bundle, allPackages.Values);

            // NOTE: All payloads should be generated before here with the exception of specific engine and ux data files.

            ArrayList fileTransfers = new ArrayList();
            string layoutDirectory = Path.GetDirectoryName(bundleFile);

            // Handle any payloads not explicitly in a container.
            foreach (string payloadName in allPayloads.Keys)
            {
                if (!payloadsAddedToContainers.ContainsKey(payloadName))
                {
                    PayloadInfoRow payload = allPayloads[payloadName];
                    if (PackagingType.Embedded == payload.Packaging)
                    {
                        payload.Container = defaultAttachedContainer.Id;
                        defaultAttachedContainer.Payloads.Add(payload);
                    }
                    else if (!String.IsNullOrEmpty(payload.FullFileName))
                    {
                        FileTransfer transfer;
                        if (FileTransfer.TryCreate(payload.FullFileName, Path.Combine(layoutDirectory, payload.Name), false, "Payload", payload.SourceLineNumbers, out transfer))
                        {
                            fileTransfers.Add(transfer);
                        }
                    }
                }
            }

            // Give the UX payloads their embedded IDs...
            for (int uxPayloadIndex = 0; uxPayloadIndex < uxPayloads.Count; ++uxPayloadIndex)
            {
                PayloadInfoRow payload = uxPayloads[uxPayloadIndex];

                // In theory, UX payloads could be embedded in the UX CAB, external to the
                // bundle EXE, or even downloaded. The current engine requires the UX to be
                // fully present before any downloading starts, so that rules out downloading.
                // Also, the burn engine does not currently copy external UX payloads into
                // the temporary UX directory correctly, so we don't allow external either.
                if (PackagingType.Embedded != payload.Packaging)
                {
                    core.OnMessage(WixWarnings.UxPayloadsOnlySupportEmbedding(payload.SourceLineNumbers, payload.FullFileName));
                    payload.Packaging = PackagingType.Embedded;
                }

                payload.EmbeddedId = String.Format(CultureInfo.InvariantCulture, BurnCommon.BurnUXContainerEmbeddedIdFormat, uxPayloadIndex);
            }

            if (this.core.EncounteredError)
            {
                return false;
            }

            // If catalog files exist, non-UX payloads should validate with the catalog
            if (catalogs.Count > 0)
            {
                foreach (PayloadInfoRow payloadInfo in allPayloads.Values)
                {
                    if (String.IsNullOrEmpty(payloadInfo.EmbeddedId))
                    {
                        VerifyPayloadWithCatalog(payloadInfo, catalogs);
                    }
                }
            }

            if (this.core.EncounteredError)
            {
                return false;
            }

            // Process the chain of packages to add them in the correct order
            // and assign the forward rollback boundaries as appropriate. Remember
            // rollback boundaries are authored as elements in the chain which
            // we re-interpret here to add them as attributes on the next available
            // package in the chain. Essentially we mark some packages as being
            // the start of a rollback boundary when installing and repairing.
            // We handle uninstall (aka: backwards) rollback boundaries after
            // we get these install/repair (aka: forward) rollback boundaries
            // defined.
            ChainInfo chain = new ChainInfo(chainTable.Rows[0]); // WixChain table always has one and only row in it.
            RollbackBoundaryInfo previousRollbackBoundary = new RollbackBoundaryInfo("WixDefaultBoundary"); // ensure there is always a rollback boundary at the beginning of the chain.
            foreach (Row row in wixGroupTable.Rows)
            {
                string rowParentName = (string)row[0];
                string rowParentType = (string)row[1];
                string rowChildName = (string)row[2];
                string rowChildType = (string)row[3];

                if ("PackageGroup" == rowParentType && "WixChain" == rowParentName && "Package" == rowChildType)
                {
                    ChainPackageInfo packageInfo = null;
                    if (allPackages.TryGetValue(rowChildName, out packageInfo))
                    {
                        if (null != previousRollbackBoundary)
                        {
                            chain.RollbackBoundaries.Add(previousRollbackBoundary);

                            packageInfo.RollbackBoundary = previousRollbackBoundary;
                            previousRollbackBoundary = null;
                        }

                        chain.Packages.Add(packageInfo);
                    }
                    else // must be a rollback boundary.
                    {
                        // Discard the next rollback boundary if we have a previously defined boundary. Of course,
                        // a boundary specifically defined will override the default boundary.
                        RollbackBoundaryInfo nextRollbackBoundary = allBoundaries[rowChildName];
                        if (null != previousRollbackBoundary && !previousRollbackBoundary.Default)
                        {
                            this.core.OnMessage(WixWarnings.DiscardedRollbackBoundary(nextRollbackBoundary.SourceLineNumbers, nextRollbackBoundary.Id));
                        }
                        else
                        {
                            previousRollbackBoundary = nextRollbackBoundary;
                        }
                    }
                }
            }

            if (null != previousRollbackBoundary)
            {
                this.core.OnMessage(WixWarnings.DiscardedRollbackBoundary(previousRollbackBoundary.SourceLineNumbers, previousRollbackBoundary.Id));
            }

            // With the forward rollback boundaries assigned, we can now go
            // through the packages with rollback boundaries and assign backward
            // rollback boundaries. Backward rollback boundaries are used when
            // the chain is going "backwards" which (AFAIK) only happens during
            // uninstall.
            //
            // Consider the scenario with three packages: A, B and C. Packages A
            // and C are marked as rollback boundary packages and package B is
            // not. The naive implementation would execute the chain like this
            // (numbers indicate where rollback boundaries would end up):
            //      install:    1 A B 2 C
            //      uninstall:  2 C B 1 A
            //
            // The uninstall chain is wrong, A and B should be grouped together
            // not C and B. The fix is to label packages with a "backwards"
            // rollback boundary used during uninstall. The backwards rollback
            // boundaries are assigned to the package *before* the next rollback
            // boundary. Using our example from above again, I'll mark the
            // backwards rollback boundaries prime (aka: with ').
            //      install:    1 A B 1' 2 C 2'
            //      uninstall:  2' C 2 1' B A 1
            //
            // If the marked boundaries are ignored during install you get the
            // same thing as above (good) and if the non-marked boundaries are
            // ignored during uninstall then A and B are correctly grouped.
            // Here's what it looks like without all the markers:
            //      install:    1 A B 2 C
            //      uninstall:  2 C 1 B A
            // Woot!
            string previousRollbackBoundaryId = null;
            ChainPackageInfo previousPackage = null;
            foreach (ChainPackageInfo package in chain.Packages)
            {
                if (null != package.RollbackBoundary)
                {
                    if (null != previousPackage)
                    {
                        previousPackage.RollbackBoundaryBackwardId = previousRollbackBoundaryId;
                    }

                    previousRollbackBoundaryId = package.RollbackBoundary.Id;
                }

                previousPackage = package;
            }

            if (!String.IsNullOrEmpty(previousRollbackBoundaryId) && null != previousPackage)
            {
                previousPackage.RollbackBoundaryBackwardId = previousRollbackBoundaryId;
            }

            // Give all embedded payloads that don't have an embedded ID yet an embedded ID.
            int payloadIndex = 0;
            foreach (PayloadInfoRow payload in allPayloads.Values)
            {
                Debug.Assert(PackagingType.Unknown != payload.Packaging);

                if (PackagingType.Embedded == payload.Packaging && String.IsNullOrEmpty(payload.EmbeddedId))
                {
                    payload.EmbeddedId = String.Format(CultureInfo.InvariantCulture, BurnCommon.BurnAttachedContainerEmbeddedIdFormat, payloadIndex);
                    ++payloadIndex;
                }
            }

            // Load the MsiProperty information...
            Table msiPropertyTable = bundle.Tables["MsiProperty"];
            if (null != msiPropertyTable && 0 < msiPropertyTable.Rows.Count)
            {
                foreach (Row row in msiPropertyTable.Rows)
                {
                    MsiPropertyInfo msiProperty = new MsiPropertyInfo(row);

                    ChainPackageInfo package;
                    if (allPackages.TryGetValue(msiProperty.PackageId, out package))
                    {
                        package.MsiProperties.Add(msiProperty);
                    }
                    else
                    {
                        core.OnMessage(WixErrors.IdentifierNotFound("Package", msiProperty.PackageId));
                    }
                }
            }

            // Load the SlipstreamMsp information...
            Table slipstreamMspTable = bundle.Tables["SlipstreamMsp"];
            if (null != slipstreamMspTable && 0 < slipstreamMspTable.Rows.Count)
            {
                foreach (Row row in slipstreamMspTable.Rows)
                {
                    string msiPackageId = (string)row[0];
                    string mspPackageId = (string)row[1];

                    if (!allPackages.ContainsKey(mspPackageId))
                    {
                        core.OnMessage(WixErrors.IdentifierNotFound("Package", mspPackageId));
                        continue;
                    }

                    ChainPackageInfo package;
                    if (!allPackages.TryGetValue(msiPackageId, out package))
                    {
                        core.OnMessage(WixErrors.IdentifierNotFound("Package", msiPackageId));
                        continue;
                    }

                    package.SlipstreamMsps.Add(mspPackageId);
                }
            }

            // Load the ExitCode information...
            Table exitCodeTable = bundle.Tables["ExitCode"];
            if (null != exitCodeTable && 0 < exitCodeTable.Rows.Count)
            {
                foreach (Row row in exitCodeTable.Rows)
                {
                    ExitCodeInfo exitCode = new ExitCodeInfo(row);

                    ChainPackageInfo package;
                    if (allPackages.TryGetValue(exitCode.PackageId, out package))
                    {
                        package.ExitCodes.Add(exitCode);
                    }
                    else
                    {
                        core.OnMessage(WixErrors.IdentifierNotFound("Package", exitCode.PackageId));
                    }
                }
            }

            // Load the CommandLine information...
            Dictionary<string, List<WixCommandLineRow>> commandLinesByPackage = new Dictionary<string, List<WixCommandLineRow>>();
            Table commandLineTable = bundle.Tables["WixCommandLine"];
            if (null != commandLineTable && 0 < commandLineTable.Rows.Count)
            {
                foreach (WixCommandLineRow row in commandLineTable.Rows)
                {
                    if (!commandLinesByPackage.ContainsKey(row.PackageId))
                    {
                        commandLinesByPackage.Add(row.PackageId, new List<WixCommandLineRow>());
                    }

                    List<WixCommandLineRow> commandLines = commandLinesByPackage[row.PackageId];
                    commandLines.Add(row);
                }
            }

            // Resolve any delayed fields before generating the manifest.
            if (0 < delayedFields.Count)
            {
                this.ResolveDelayedFields(bundle, delayedFields, variableCache, null);
            }

            // Process WixApprovedExeForElevation rows.
            Table wixApprovedExeForElevationTable = bundle.Tables["WixApprovedExeForElevation"];
            List<ApprovedExeForElevation> approvedExesForElevation = new List<ApprovedExeForElevation>();
            if (null != wixApprovedExeForElevationTable && 0 < wixApprovedExeForElevationTable.Rows.Count)
            {
                foreach (WixApprovedExeForElevationRow wixApprovedExeForElevationRow in wixApprovedExeForElevationTable.Rows)
                {
                    ApprovedExeForElevation approvedExeForElevation = new ApprovedExeForElevation(wixApprovedExeForElevationRow);
                    approvedExesForElevation.Add(approvedExeForElevation);
                }
            }

            // Set the overridable bundle provider key.
            this.SetBundleProviderKey(bundle, bundleInfo);

            // Import or generate dependency providers for packages in the manifest.
            this.ProcessDependencyProviders(bundle, allPackages);

            // Generate the core-defined BA manifest tables...
            this.GenerateBAManifestPackageTables(bundle, chain.Packages);

            this.GenerateBAManifestPayloadTables(bundle, chain.Packages, allPayloads);

            foreach (BinderExtension extension in this.extensions)
            {
                extension.BundleFinalize(bundle);
            }

            // Start creating the bundle.
            this.PopulateBundleInfoFromChain(bundleInfo, chain.Packages);
            this.PopulateChainInfoTables(bundle, bundleInfo, chain.Packages);
            this.GenerateBAManifestBundleTables(bundle, bundleInfo);

            // Copy the burn.exe to a writable location then mark it to be moved to its
            // final build location.
            string stubPlatform;
            if (Platform.X64 == bundleInfo.Platform) // today, the x64 Burn uses the x86 stub.
            {
                stubPlatform = "x86";
            }
            else
            {
                stubPlatform = bundleInfo.Platform.ToString();
            }
            string wixExeDirectory = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), stubPlatform);
            string stubFile = Path.Combine(wixExeDirectory, "burn.exe");
            string bundleTempPath = Path.Combine(this.TempFilesLocation, Path.GetFileName(bundleFile));

            this.core.OnMessage(WixVerboses.GeneratingBundle(bundleTempPath, stubFile));
            File.Copy(stubFile, bundleTempPath, true);
            File.SetAttributes(bundleTempPath, FileAttributes.Normal);

            FileTransfer bundleTransfer;
            if (FileTransfer.TryCreate(bundleTempPath, bundleFile, true, "Bundle", bundleInfo.SourceLineNumbers, out bundleTransfer))
            {
                bundleTransfer.Built = true;
                fileTransfers.Add(bundleTransfer);
            }

            // Create our manifests, CABs and final EXE...
            string baManifestPath = Path.Combine(this.TempFilesLocation, "bundle-BootstrapperApplicationData.xml");
            this.CreateBootstrapperApplicationManifest(bundle, baManifestPath, uxPayloads);

            // Add the bootstrapper application manifest to the set of UX payloads.
            PayloadInfoRow baManifestPayload = PayloadInfoRow.Create(null /*TODO*/, bundle, Common.GenerateIdentifier("ux", true, "BootstrapperApplicationData.xml"),
                "BootstrapperApplicationData.xml", baManifestPath, false, true, null, burnUXContainer.Id, PackagingType.Embedded);
            baManifestPayload.EmbeddedId = string.Format(CultureInfo.InvariantCulture, BurnCommon.BurnUXContainerEmbeddedIdFormat, uxPayloads.Count);
            uxPayloads.Add(baManifestPayload);

            // Create all the containers except the UX container first so the manifest in the UX container can contain all size and hash information.
            foreach (ContainerInfo container in containers.Values)
            {
                if (Compiler.BurnUXContainerId != container.Id && 0 < container.Payloads.Count)
                {
                    this.CreateContainer(container, null);
                }
            }

            string manifestPath = Path.Combine(this.TempFilesLocation, "bundle-manifest.xml");
            this.CreateBurnManifest(bundleFile, bundleInfo, bundleUpdateRow, updateRegistrationInfo, manifestPath, allRelatedBundles, allVariables, orderedSearches, allPayloads, chain, containers, catalogs, bundle.Tables["WixBundleTag"], approvedExesForElevation, commandLinesByPackage);

            this.UpdateBurnResources(bundleTempPath, bundleFile, bundleInfo);

            // update the .wixburn section to point to at the UX and attached container(s) then attach the container(s) if they should be attached.
            using (BurnWriter writer = BurnWriter.Open(bundleTempPath, this.core))
            {
                FileInfo burnStubFile = new FileInfo(bundleTempPath);
                writer.InitializeBundleSectionData(burnStubFile.Length, bundleInfo.BundleId);

                // Always create UX container and attach it first
                this.CreateContainer(burnUXContainer, manifestPath);
                writer.AppendContainer(burnUXContainer.TempPath, BurnWriter.Container.UX);

                // Now append all other attached containers
                foreach (ContainerInfo container in containers.Values)
                {
                    if (container.Type == "attached")
                    {
                        // The container was only created if it had payloads.
                        if (Compiler.BurnUXContainerId != container.Id && 0 < container.Payloads.Count)
                        {
                            writer.AppendContainer(container.TempPath, BurnWriter.Container.Attached);
                        }
                    }
                }
            }

            // Output the bundle to a file
            if (null != this.pdbFile)
            {
                Pdb pdb = new Pdb(null);
                pdb.Output = bundle;
                pdb.Save(this.pdbFile, null, this.WixVariableResolver, this.TempFilesLocation);
            }

            // Add detached containers to the list of file transfers.
            foreach (ContainerInfo container in containers.Values)
            {
                if ("detached" == container.Type)
                {
                    FileTransfer transfer;
                    if (FileTransfer.TryCreate(Path.Combine(this.TempFilesLocation, container.Name), Path.Combine(layoutDirectory, container.Name), true, "Container", container.SourceLineNumbers, out transfer))
                    {
                        transfer.Built = true;
                        fileTransfers.Add(transfer);
                    }
                }
            }

            // layout media
            string bundleFilename = Path.GetFileName(bundleFile);
            if ("setup.exe".Equals(bundleFilename, StringComparison.OrdinalIgnoreCase))
            {
                this.core.OnMessage(WixErrors.InsecureBundleFilename(bundleFilename));
            }

            try
            {
                this.core.OnMessage(WixVerboses.LayingOutMedia());
                this.LayoutMedia(fileTransfers, this.suppressAclReset);
            }
            finally
            {
                if (!String.IsNullOrEmpty(this.contentsFile))
                {
                    this.CreateContentsFile(this.contentsFile, allPayloads.Values);
                }

                if (!String.IsNullOrEmpty(this.outputsFile))
                {
                    this.CreateOutputsFile(this.outputsFile, fileTransfers, this.pdbFile);
                }

                if (!String.IsNullOrEmpty(this.builtOutputsFile))
                {
                    this.CreateBuiltOutputsFile(this.builtOutputsFile, fileTransfers, this.pdbFile);
                }
            }

            return !this.core.EncounteredError;
        }
Example #6
0
File: Pdb.cs Project: zooba/wix3
        /// <summary>
        /// Processes an XmlReader and builds up the pdb object.
        /// </summary>
        /// <param name="reader">Reader to get data from.</param>
        /// <param name="suppressVersionCheck">Suppresses wix.dll version mismatch check.</param>
        /// <returns>The Pdb represented by the Xml.</returns>
        internal static Pdb Parse(XmlReader reader, bool suppressVersionCheck)
        {
            Debug.Assert("wixPdb" == reader.LocalName);

            bool empty = reader.IsEmptyElement;
            Pdb pdb = new Pdb(SourceLineNumberCollection.FromUri(reader.BaseURI));
            Version version = null;

            while (reader.MoveToNextAttribute())
            {
                switch (reader.LocalName)
                {
                    case "version":
                        version = new Version(reader.Value);
                        break;
                    default:
                        if (!reader.NamespaceURI.StartsWith("http://www.w3.org/", StringComparison.Ordinal))
                        {
                            throw new WixException(WixErrors.UnexpectedAttribute(SourceLineNumberCollection.FromUri(reader.BaseURI), "wixPdb", reader.Name));
                        }
                        break;
                }
            }

            if (null != version)
            {
                if (0 != currentVersion.CompareTo(version))
                {
                    throw new WixException(WixErrors.VersionMismatch(SourceLineNumberCollection.FromUri(reader.BaseURI), "wixPdb", version.ToString(), currentVersion.ToString()));
                }
            }

            // loop through the rest of the pdb building up the Output object
            if (!empty)
            {
                bool done = false;

                // loop through all the fields in a row
                while (!done && reader.Read())
                {
                    switch (reader.NodeType)
                    {
                        case XmlNodeType.Element:
                            switch (reader.LocalName)
                            {
                                case "wixOutput":
                                    pdb.output = Output.Parse(reader, suppressVersionCheck);
                                    break;
                                default:
                                    throw new WixException(WixErrors.UnexpectedElement(SourceLineNumberCollection.FromUri(reader.BaseURI), "wixPdb", reader.Name));
                            }
                            break;
                        case XmlNodeType.EndElement:
                            done = true;
                            break;
                    }
                }

                if (!done)
                {
                    throw new WixException(WixErrors.ExpectedEndElement(SourceLineNumberCollection.FromUri(reader.BaseURI), "wixOutput"));
                }
            }

            return pdb;
        }