Esempio n. 1
1
        private static IList<SoftwareTag> CollectPackageTags(Output bundle)
        {
            List<SoftwareTag> tags = new List<SoftwareTag>();
            Table packageTable = bundle.Tables["ChainPackageInfo"];
            if (null != packageTable)
            {
                Table payloadTable = bundle.Tables["PayloadInfo"];
                RowDictionary<PayloadInfoRow> payloads = new RowDictionary<PayloadInfoRow>(payloadTable);

                foreach (Row row in packageTable.Rows)
                {
                    Compiler.ChainPackageType packageType = (Compiler.ChainPackageType)Enum.Parse(typeof(Compiler.ChainPackageType), (string)row[1], true);
                    if (Compiler.ChainPackageType.Msi == packageType)
                    {
                        string packagePayloadId = (string)row[2];
                        PayloadInfoRow payload = (PayloadInfoRow)payloads[packagePayloadId];

                        using (Database db = new Database(payload.FullFileName))
                        {
                            if (db.Tables.Contains("SoftwareIdentificationTag"))
                            {
                                using (View view = db.OpenView("SELECT `Regid`, `UniqueId`, `Type` FROM `SoftwareIdentificationTag`"))
                                {
                                    view.Execute();
                                    while (true)
                                    {
                                        using (Record record = view.Fetch())
                                        {
                                            if (null == record)
                                            {
                                                break;
                                            }

                                            TagType type = String.IsNullOrEmpty(record.GetString(3)) ? TagType.Unknown : (TagType)Enum.Parse(typeof(TagType), record.GetString(3));
                                            tags.Add(new SoftwareTag() { Regid = record.GetString(1), Id = record.GetString(2), Type = type });
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            return tags;
        }
Esempio n. 2
0
        public void WhenTryingToGetAValueAndTheKeyExistsShould()
        {
            //Arrange
            var key                         = 01;
            var expectedValue               = "expectedValue";
            var comparer                    = Comparer <int> .Default;
            var mockEqualityService         = MockRepository.GenerateMock <IComparer <Cell <int, string> > >();
            var mockEqualityServiceProvider = MockRepository.GenerateMock <IEqualityServiceProvider <int> >();

            mockEqualityServiceProvider.Stub(x => x.GetKeyComparer(comparer)).Return(comparer);
            mockEqualityService
            .Stub(s => s.Compare(
                      Arg <Cell <int, string> > .Matches(x => x.Key == key),
                      Arg <Cell <int, string> > .Matches(x => x.Key == key)))
            .Return(0);
            var sut = new RowDictionary <int, string>(comparer, mockEqualityServiceProvider);

            sut.Add(key, expectedValue);
            string resultValue;

            //Act
            var resultBooleanValue = sut.TryGetValue(key, out resultValue);

            //Assert
            Assert.That(resultBooleanValue, Is.True);
            Assert.That(resultValue, Is.EqualTo(expectedValue));
        }
Esempio n. 3
0
		public static void Main()
		{
            Spreadsheet.Spreadsheets = new SpreadsheetsDictionary();
		    var spreadsheetsDictionary = new SpreadsheetDictionary();
            Spreadsheet.Spreadsheets.Add(0, spreadsheetsDictionary);
		    var row = new RowDictionary();
            spreadsheetsDictionary.Add(0, row);

		    var cellA1 = new Cell(0, 0, 0);
		    cellA1.Value = "250";
		    var cellB1 = new Cell(0, 0, 1);
            cellB1.Value = "250";
		    var cellC1 = new Cell(0, 0, 2);
            cellC1.Formula = "800 - SUM(A1:B1) + 100";
		    cellC1.HasFormula = true;

            row.Add(0, cellA1);
            row.Add(1, cellB1);
            row.Add(2, cellC1);

            //var spreadsheet = new Spreadsheet();
		    //spreadsheet.Calc();

		    var parsedCell = Spreadsheet.Spreadsheets[0][0][2];
		    var value = parsedCell.UpdateValue();
		    value = value;
		}
Esempio n. 4
0
        public void WhenTryingToGetAValueAndTheKeyDoesNotExistShould()
        {
            //Arrange
            var key = "key";
            var thisKeyDoesNotExist         = "thisKeyDoesNotExist";
            var expectedValue               = "expectedValue";
            var comparer                    = (IComparer <string>)StringComparer.InvariantCultureIgnoreCase;
            var mockEqualityService         = MockRepository.GenerateMock <IComparer <Cell <string, string> > >();
            var mockEqualityServiceProvider = MockRepository.GenerateMock <IEqualityServiceProvider <string> >();

            mockEqualityServiceProvider.Stub(x => x.GetKeyComparer(comparer)).Return(comparer);
            mockEqualityService
            .Stub(s => s.Compare(
                      Arg <Cell <string, string> > .Matches(x => x.Key == key),
                      Arg <Cell <string, string> > .Matches(x => x.Key == thisKeyDoesNotExist)))
            .Return(-1);

            var sut = new RowDictionary <string, string>(comparer, mockEqualityServiceProvider);

            sut.Add(key, expectedValue);
            string resultValue;

            //Act
            var resultBooleanValue = sut.TryGetValue(thisKeyDoesNotExist, out resultValue);

            //Assert
            Assert.That(resultBooleanValue, Is.False);
        }
Esempio n. 5
0
        /// <param name="output">Output to generate image for.</param>
        /// <param name="fileTransfers">Array of files to be transfered.</param>
        /// <param name="layoutDirectory">The directory in which the image should be layed out.</param>
        /// <param name="compressed">Flag if source image should be compressed.</param>
        /// <returns>The uncompressed file rows.</returns>
        public void Execute()
        {
            RowDictionary <WixMediaRow> wixMediaRows = new RowDictionary <WixMediaRow>(this.WixMediaTable);

            this.lastCabinetAddedToMediaTable = new Dictionary <string, string>();

            this.SetCabbingThreadCount();

            // Send Binder object to Facilitate NewCabNamesCallBack Callback
            CabinetBuilder cabinetBuilder = new CabinetBuilder(this.CabbingThreadCount, Marshal.GetFunctionPointerForDelegate(this.newCabNamesCallBack));

            // Supply Compile MediaTemplate Attributes to Cabinet Builder
            int MaximumCabinetSizeForLargeFileSplitting;
            int MaximumUncompressedMediaSize;

            this.GetMediaTemplateAttributes(out MaximumCabinetSizeForLargeFileSplitting, out MaximumUncompressedMediaSize);
            cabinetBuilder.MaximumCabinetSizeForLargeFileSplitting = MaximumCabinetSizeForLargeFileSplitting;
            cabinetBuilder.MaximumUncompressedMediaSize            = MaximumUncompressedMediaSize;

            foreach (var entry in this.FileRowsByCabinet)
            {
                MediaRow mediaRow = entry.Key;
                IEnumerable <FileFacade> files            = entry.Value;
                CompressionLevel         compressionLevel = this.DefaultCompressionLevel;

                WixMediaRow wixMediaRow       = null;
                string      mediaLayoutFolder = null;

                if (wixMediaRows.TryGetValue(mediaRow.GetKey(), out wixMediaRow))
                {
                    mediaLayoutFolder = wixMediaRow.Layout;

                    if (wixMediaRow.CompressionLevel.HasValue)
                    {
                        compressionLevel = wixMediaRow.CompressionLevel.Value;
                    }
                }

                string cabinetDir = this.ResolveMedia(mediaRow, mediaLayoutFolder, this.LayoutDirectory);

                CabinetWorkItem cabinetWorkItem = this.CreateCabinetWorkItem(this.Output, cabinetDir, mediaRow, compressionLevel, files, this.fileTransfers);
                if (null != cabinetWorkItem)
                {
                    cabinetBuilder.Enqueue(cabinetWorkItem);
                }
            }

            // stop processing if an error previously occurred
            if (Messaging.Instance.EncounteredError)
            {
                return;
            }

            // create queued cabinets with multiple threads
            cabinetBuilder.CreateQueuedCabinets();
            if (Messaging.Instance.EncounteredError)
            {
                return;
            }
        }
        public void ShouldBeAbleToSpecifyEqualityServiceToUse()
        {
            //Arrange
            var equalityService = StringComparer.CurrentCulture;

            //Act
            var sut = new RowDictionary <string, string>(equalityService);

            //Assert
            Assert.That(sut, Is.TypeOf <RowDictionary <string, string> >());
        }
Esempio n. 7
0
        public static string ConfigurationStringGenerator()
        {
            string KiesString = "";

            foreach (var item in ConfigurationList)
            {
                var MyKey = RowDictionary.First(x => x.Value.ParamName == item).Key;
                KiesString += MyKey;
            }
            ;
            return(KiesString);
        }
Esempio n. 8
0
        public void WhenInstantiatingANewDictionaryShouldCallGetComparer()
        {
            //Arrange
            var comparer = Comparer <int> .Default;
            var mockEqualityServiceProvider = MockRepository.GenerateMock <IEqualityServiceProvider <int> >();

            //Act
            var sut = new RowDictionary <int, string>(comparer, mockEqualityServiceProvider);

            //Assert
            mockEqualityServiceProvider.AssertWasCalled(x => x.GetKeyComparer(comparer));
        }
Esempio n. 9
0
            /// <summary>
            /// Initializes a new instance of the <see cref="Table"/> class.
            /// </summary>
            /// <param name="name">The name of the table.</param>
            /// <param name="db">The <see cref="Db"/> to which this <see cref="Table"/> is attached.</param>
            public Table(string name, Db db)
            {
                Util.ThrowIfStringParameterNullOrEmpty(name, "name");
                Util.ThrowIfParameterNull(db, "db");

                _rows     = new RowDictionary(this);
                _name     = name.ToLower();
                _db       = db;
                _xapiType = TypeCache.GetProxyType(name);

                _rows.Changed += delegate { OnChanged(EventArgs.Empty); };
            }
Esempio n. 10
0
        /// <summary>
        /// Reorders Any WixSearch items.
        /// </summary>
        /// <param name="output">Output containing the tables to process.</param>
        private void ReorderWixSearch(Output output)
        {
            Table wixSearchTable = output.Tables["WixSearch"];

            if (null == wixSearchTable || wixSearchTable.Rows.Count == 0)
            {
                // nothing to do!
                return;
            }

            RowDictionary rowDictionary = new RowDictionary();

            foreach (Row row in wixSearchTable.Rows)
            {
                rowDictionary.AddRow(row);
            }

            Constraints constraints            = new Constraints();
            Table       wixSearchRelationTable = output.Tables["WixSearchRelation"];

            if (null != wixSearchRelationTable && wixSearchRelationTable.Rows.Count > 0)
            {
                // add relational info to our data...
                foreach (Row row in wixSearchRelationTable.Rows)
                {
                    constraints.AddConstraint((string)row[0], (string)row[1]);
                }
            }

            this.FindCircularReference(constraints);

            if (this.Core.EncounteredError)
            {
                return;
            }

            this.FlattenDependentReferences(constraints);

            // Reorder by topographical sort (http://en.wikipedia.org/wiki/Topological_sorting)
            // We use a variation of Kahn (1962) algorithm as described in
            // Wikipedia, with the additional criteria that start nodes are sorted
            // lexicographically at each step to ensure a deterministic ordering
            // based on 'after' dependencies and ID.
            TopologicalSort sorter    = new TopologicalSort();
            List <string>   sortedIds = sorter.Sort(rowDictionary.Keys, constraints);

            // Now, re-write the table with the searches in order...
            wixSearchTable.Rows.Clear();
            foreach (string id in sortedIds)
            {
                wixSearchTable.Rows.Add(rowDictionary[id]);
            }
        }
        public void ShouldThrowAnExceptionIfTheKeyDoesNotExist()
        {
            //Arrange
            var sut = new RowDictionary <string, string>
            {
                { "key01", "Value01" }
            };
            string result;

            //Act
            //Assert
            Assert.That(() => result = sut["keyDoesNotExist"], Throws.TypeOf <KeyNotFoundException>());
        }
Esempio n. 12
0
        private static IList <SoftwareTag> CollectPackageTags(Output bundle)
        {
            List <SoftwareTag> tags = new List <SoftwareTag>();
            Table packageTable      = bundle.Tables["ChainPackageInfo"];

            if (null != packageTable)
            {
                Table payloadTable = bundle.Tables["PayloadInfo"];
                RowDictionary <PayloadInfoRow> payloads = new RowDictionary <PayloadInfoRow>(payloadTable);

                foreach (Row row in packageTable.Rows)
                {
                    Compiler.ChainPackageType packageType = (Compiler.ChainPackageType)Enum.Parse(typeof(Compiler.ChainPackageType), (string)row[1], true);
                    if (Compiler.ChainPackageType.Msi == packageType)
                    {
                        string         packagePayloadId = (string)row[2];
                        PayloadInfoRow payload          = (PayloadInfoRow)payloads[packagePayloadId];

                        using (Database db = new Database(payload.FullFileName))
                        {
                            if (db.Tables.Contains("SoftwareIdentificationTag"))
                            {
                                using (View view = db.OpenView("SELECT `Regid`, `UniqueId`, `Type` FROM `SoftwareIdentificationTag`"))
                                {
                                    view.Execute();
                                    while (true)
                                    {
                                        using (Record record = view.Fetch())
                                        {
                                            if (null == record)
                                            {
                                                break;
                                            }

                                            TagType type = String.IsNullOrEmpty(record.GetString(3)) ? TagType.Unknown : (TagType)Enum.Parse(typeof(TagType), record.GetString(3));
                                            tags.Add(new SoftwareTag()
                                            {
                                                Regid = record.GetString(1), Id = record.GetString(2), Type = type
                                            });
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            return(tags);
        }
        public void ShouldBeAbleToRetrieveTheValueUsingTheKeyWhenThereIsMoreThanOneValueInserted()
        {
            //Arrange
            var key          = 41;
            var anotherValue = "anotherValue";
            var sut          = new RowDictionary <int, string> {
                { 7, "abc" }, { 410, "era" }, { 8, "era" }, { key, anotherValue }
            };

            //Act
            var result = sut[key];

            //Assert
            Assert.That(result, Is.EqualTo(anotherValue));
        }
Esempio n. 14
0
        public void ShouldSearchByKeyCaseInsensitiveLowerExample()
        {
            //Arrange
            var key      = "keyUPPERandlower";
            var expected = "expected";
            var sut      = new RowDictionary <string, string> {
                { key, expected }
            };

            //Act
            var result03 = sut[key.ToLower()];

            //Assert
            Assert.That(result03, Is.EqualTo(expected));
        }
        public void ShouldBeAbleToAddUsingBracket()
        {
            //Arrange
            var myKey   = new { FirstName = "ABC", LastName = "DFG" };
            var myValue = "myValue";
            var sut     = new RowDictionary <object, string>();

            sut[myKey] = myValue;

            //Act
            var result = sut[myKey];

            //Assert
            Assert.That(result, Is.EqualTo(myValue));
        }
        public void ShouldBeAbleToRetrieveTheValueUsingTheKeyWhenThereIsOnlyOneValueInserted()
        {
            //Arrange
            var key           = 55;
            var expectedValue = "expectedValue";
            var sut           = new RowDictionary <int, string> {
                { key, expectedValue }
            };

            //Act
            var result = sut[key];

            //Assert
            Assert.That(result, Is.EqualTo(expectedValue));
        }
Esempio n. 17
0
        public static RowDictionary RowsToDict(RowsRet rows)
        {
            RowDictionary rowDict =
                new RowDictionary();

            List <string> .Enumerator headerRow =
                rows.Rows[0].Cols.GetEnumerator();

            foreach (string cell in rows.Rows[1].Cols)
            {
                headerRow.MoveNext();
                rowDict.Add(headerRow.Current, cell);
            }
            return(rowDict);
        }
Esempio n. 18
0
        public void Execute()
        {
            Dictionary <MediaRow, List <FileFacade> > filesByCabinetMedia = new Dictionary <MediaRow, List <FileFacade> >();

            RowDictionary <MediaRow> mediaRows = new RowDictionary <MediaRow>();

            List <FileFacade> uncompressedFiles = new List <FileFacade>();

            MediaRow mergeModuleMediaRow = null;
            Table    mediaTable          = this.Output.Tables["Media"];
            Table    mediaTemplateTable  = this.Output.Tables["WixMediaTemplate"];

            // If both tables are authored, it is an error.
            if ((mediaTemplateTable != null && mediaTemplateTable.Rows.Count > 0) && (mediaTable != null && mediaTable.Rows.Count > 1))
            {
                throw new WixException(WixErrors.MediaTableCollision(null));
            }

            // When building merge module, all the files go to "#MergeModule.CABinet".
            if (OutputType.Module == this.Output.Type)
            {
                Table mergeModuleMediaTable = new Table(null, this.TableDefinitions["Media"]);
                mergeModuleMediaRow         = (MediaRow)mergeModuleMediaTable.CreateRow(null);
                mergeModuleMediaRow.Cabinet = "#MergeModule.CABinet";

                filesByCabinetMedia.Add(mergeModuleMediaRow, new List <FileFacade>());
            }

            if (OutputType.Module == this.Output.Type || null == mediaTemplateTable)
            {
                this.ManuallyAssignFiles(mediaTable, mergeModuleMediaRow, this.FileFacades, filesByCabinetMedia, mediaRows, uncompressedFiles);
            }
            else
            {
                this.AutoAssignFiles(mediaTable, this.FileFacades, filesByCabinetMedia, mediaRows, uncompressedFiles);
            }

            this.FileFacadesByCabinetMedia = new Dictionary <MediaRow, IEnumerable <FileFacade> >();

            foreach (var mediaRowWithFiles in filesByCabinetMedia)
            {
                this.FileFacadesByCabinetMedia.Add(mediaRowWithFiles.Key, mediaRowWithFiles.Value);
            }

            this.MediaRows = mediaRows;

            this.UncompressedFileFacades = uncompressedFiles;
        }
Esempio n. 19
0
        public void ShouldBeAbleToRetrieveTheValueUsingTheKeyWhenTheKeyIsNonPrimitive()
        {
            //Arrange
            var          myKey = new { FirstName = "ABC", LastName = "DFG" };
            const string whenTheKeyIsAnObject = "WhenTheKeyIsAnObject";
            var          sut = new RowDictionary <object, string>();

            sut.Add(myKey, whenTheKeyIsAnObject);
            string result;

            //Act
            sut.TryGetValue(myKey, out result);

            //Assert
            Assert.That(result, Is.EqualTo(whenTheKeyIsAnObject));
        }
Esempio n. 20
0
        public void ShouldBeAbleToAddANewValueAndRetriveTheSameValueUsingTheSameKey()
        {
            //Arrange
            var key           = "key";
            var expectedValue = "Hola mundo";
            var sut           = new RowDictionary <string, string>();

            sut.Add(key, expectedValue);
            string result;

            //Act
            sut.TryGetValue(key, out result);

            //Assert
            Assert.That(result, Is.EqualTo(expectedValue));
        }
Esempio n. 21
0
        public void ShouldBeAbleToRetrieveTheValueUsingTheKeyWhenThereIsOnlyOneValueInserted()
        {
            //Arrange
            var key           = 01;
            var expectedValue = "expectedValue";
            var sut           = new RowDictionary <int, string>();

            sut.Add(key, expectedValue);
            string result;

            //Act
            sut.TryGetValue(key, out result);

            //Assert
            Assert.That(result, Is.EqualTo(expectedValue));
        }
        public void ShouldBeAbleToRetrieveTheValueUsingTheKeyWhenTheKeyIsNonPrimitive()
        {
            //Arrange
            var myKey = new { FirstName = "ABC", LastName = "DFG" };
            var WhenTheKeyIsAnObject = "WhenTheKeyIsAnObject";
            var sut = new RowDictionary <object, string>
            {
                { myKey, WhenTheKeyIsAnObject }
            };

            //Act
            var result = sut[myKey];

            //Assert
            Assert.That(result, Is.EqualTo(WhenTheKeyIsAnObject));
        }
Esempio n. 23
0
        public void ShouldIterateExactlyAsManyTimesAsKeysAdded()
        {
            //Arrange
            var sut = new RowDictionary <int, string>();

            sut.Add(01, "Value01");
            sut.Add(02, "Value02");
            sut.Add(03, "Value03");
            sut.Add(04, "Value04");
            sut.Add(05, "Value05");
            sut.Add(06, "Value06");

            //Act
            var totalItems = sut.Cast <object>().Count();

            //Assert
            Assert.That(totalItems, Is.EqualTo(6));
        }
Esempio n. 24
0
        public static RowDictionary RowsToDict(Row header, Row row)
        {
            RowDictionary rowDict =
                new RowDictionary();

            List <string> .Enumerator headerRow =
                header.Cols.GetEnumerator();

            foreach (string cell in row.Cols)
            {
                headerRow.MoveNext();
                if (!rowDict.ContainsKey(headerRow.Current))
                {
                    rowDict.Add(headerRow.Current, cell);
                }
            }

            return(rowDict);
        }
Esempio n. 25
0
        public void WhenGettingAValueAndTheKeyExistsShould()
        {
            //Arrange
            var key           = 01;
            var expectedValue = "expectedValue";
            var comparer      = Comparer <int> .Default;
            var mockEqualityServiceProvider = MockRepository.GenerateMock <IEqualityServiceProvider <int> >();

            mockEqualityServiceProvider.Stub(x => x.GetKeyComparer(comparer)).Return(comparer);
            var sut = new RowDictionary <int, string>(comparer, mockEqualityServiceProvider);

            sut.Add(key, expectedValue);
            string resultValue;

            //Act
            resultValue = sut[key];

            //Assert
            Assert.That(resultValue, Is.EqualTo(expectedValue));
        }
Esempio n. 26
0
        //----------------------------------
        public static string SentStringGenerator()
        {
            string ObjectString = "";

            foreach (var item in ConfigurationList)
            {
                var MyValue = RowDictionary.First(x => x.Value.Name == item).Value.Value;
                ObjectString += MyValue.ToString();
                if (ConfigurationList.IndexOf(item) == ConfigurationList.Count - 1 && VM.ParamConfigurationList.Count == 0)
                {
                    ObjectString += ";";
                }
                else
                {
                    ObjectString += "|";
                }
            }
            ;
            return(ObjectString);
        }
Esempio n. 27
0
        public void Execute()
        {
            if (null != this.WixBBControlTable)
            {
                RowDictionary <BBControlRow> bbControlRows = new RowDictionary <BBControlRow>(this.BBControlTable);
                foreach (Row wixRow in this.WixBBControlTable.Rows)
                {
                    BBControlRow bbControlRow = bbControlRows.Get(wixRow.GetPrimaryKey());
                    bbControlRow.Text = this.ReadTextFile(bbControlRow.SourceLineNumbers, wixRow.FieldAsString(2));
                }
            }

            if (null != this.WixControlTable)
            {
                RowDictionary <ControlRow> controlRows = new RowDictionary <ControlRow>(this.ControlTable);
                foreach (Row wixRow in this.WixControlTable.Rows)
                {
                    ControlRow controlRow = controlRows.Get(wixRow.GetPrimaryKey());
                    controlRow.Text = this.ReadTextFile(controlRow.SourceLineNumbers, wixRow.FieldAsString(2));
                }
            }
        }
Esempio n. 28
0
        public void Execute()
        {
            RowDictionary <WixBundleExePackageRow> exePackages = new RowDictionary <WixBundleExePackageRow>(this.ExePackageTable);
            RowDictionary <WixBundleMsiPackageRow> msiPackages = new RowDictionary <WixBundleMsiPackageRow>(this.MsiPackageTable);
            RowDictionary <WixBundleMspPackageRow> mspPackages = new RowDictionary <WixBundleMspPackageRow>(this.MspPackageTable);
            RowDictionary <WixBundleMsuPackageRow> msuPackages = new RowDictionary <WixBundleMsuPackageRow>(this.MsuPackageTable);

            Dictionary <string, PackageFacade> facades = new Dictionary <string, PackageFacade>(this.PackageTable.Rows.Count);

            foreach (WixBundlePackageRow package in this.PackageTable.Rows)
            {
                string        id     = package.WixChainItemId;
                PackageFacade facade = null;

                switch (package.Type)
                {
                case WixBundlePackageType.Exe:
                    facade = new PackageFacade(package, exePackages.Get(id));
                    break;

                case WixBundlePackageType.Msi:
                    facade = new PackageFacade(package, msiPackages.Get(id));
                    break;

                case WixBundlePackageType.Msp:
                    facade = new PackageFacade(package, mspPackages.Get(id));
                    break;

                case WixBundlePackageType.Msu:
                    facade = new PackageFacade(package, msuPackages.Get(id));
                    break;
                }

                facades.Add(id, facade);
            }

            this.PackageFacades = facades;
        }
Esempio n. 29
0
        public void Execute()
        {
            List <FileFacade> facades = new List <FileFacade>(this.FileTable.Rows.Count);

            RowDictionary <WixFileRow>           wixFiles        = new RowDictionary <WixFileRow>(this.WixFileTable);
            RowDictionary <WixDeltaPatchFileRow> deltaPatchFiles = new RowDictionary <WixDeltaPatchFileRow>(this.WixDeltaPatchFileTable);

            foreach (FileRow file in this.FileTable.Rows)
            {
                WixDeltaPatchFileRow deltaPatchFile = null;

                deltaPatchFiles.TryGetValue(file.File, out deltaPatchFile);

                facades.Add(new FileFacade(file, wixFiles[file.File], deltaPatchFile));
            }

            if (null != this.WixDeltaPatchSymbolPathsTable)
            {
                this.ResolveDeltaPatchSymbolPaths(deltaPatchFiles, facades);
            }

            this.FileFacades = facades;
        }
Esempio n. 30
0
File: Binder.cs Progetto: zooba/wix3
        private void AutomaticallySlipstreamPatches(Output bundle, ICollection<ChainPackageInfo> packages)
        {
            List<ChainPackageInfo> msiPackages = new List<ChainPackageInfo>();
            Dictionary<string, List<WixBundlePatchTargetCodeRow>> targetsProductCode = new Dictionary<string, List<WixBundlePatchTargetCodeRow>>();
            Dictionary<string, List<WixBundlePatchTargetCodeRow>> targetsUpgradeCode = new Dictionary<string, List<WixBundlePatchTargetCodeRow>>();

            foreach (ChainPackageInfo package in packages)
            {
                if (Compiler.ChainPackageType.Msi == package.ChainPackageType)
                {
                    // Keep track of all MSI packages.
                    msiPackages.Add(package);
                }
                else if (Compiler.ChainPackageType.Msp == package.ChainPackageType && package.Slipstream)
                {
                    // Index target ProductCodes and UpgradeCodes for slipstreamed MSPs.
                    foreach (WixBundlePatchTargetCodeRow row in package.TargetCodes)
                    {
                        if (row.TargetsProductCode)
                        {
                            List<WixBundlePatchTargetCodeRow> rows;
                            if (!targetsProductCode.TryGetValue(row.TargetCode, out rows))
                            {
                                rows = new List<WixBundlePatchTargetCodeRow>();
                                targetsProductCode.Add(row.TargetCode, rows);
                            }

                            rows.Add(row);
                        }
                        else if (row.TargetsUpgradeCode)
                        {
                            List<WixBundlePatchTargetCodeRow> rows;
                            if (!targetsUpgradeCode.TryGetValue(row.TargetCode, out rows))
                            {
                                rows = new List<WixBundlePatchTargetCodeRow>();
                                targetsUpgradeCode.Add(row.TargetCode, rows);
                            }
                        }
                    }
                }
            }

            Table slipstreamMspTable = bundle.EnsureTable(this.core.TableDefinitions["SlipstreamMsp"]);
            RowDictionary<Row> slipstreamMspRows = new RowDictionary<Row>(slipstreamMspTable);

            // Loop through the MSI and slipstream patches targeting it.
            foreach (ChainPackageInfo msi in msiPackages)
            {
                List<WixBundlePatchTargetCodeRow> rows;
                if (targetsProductCode.TryGetValue(msi.ProductCode, out rows))
                {
                    foreach (WixBundlePatchTargetCodeRow row in rows)
                    {
                        Row slipstreamMspRow = slipstreamMspTable.CreateRow(row.SourceLineNumbers, false);
                        slipstreamMspRow[0] = msi.Id;
                        slipstreamMspRow[1] = row.MspPackageId;

                        if (slipstreamMspRows.TryAdd(slipstreamMspRow))
                        {
                            slipstreamMspTable.Rows.Add(slipstreamMspRow);
                        }
                    }

                    rows = null;
                }

                if (!String.IsNullOrEmpty(msi.UpgradeCode) && targetsUpgradeCode.TryGetValue(msi.UpgradeCode, out rows))
                {
                    foreach (WixBundlePatchTargetCodeRow row in rows)
                    {
                        Row slipstreamMspRow = slipstreamMspTable.CreateRow(row.SourceLineNumbers, false);
                        slipstreamMspRow[0] = msi.Id;
                        slipstreamMspRow[1] = row.MspPackageId;

                        if (slipstreamMspRows.TryAdd(slipstreamMspRow))
                        {
                            slipstreamMspTable.Rows.Add(slipstreamMspRow);
                        }
                    }

                    rows = null;
                }
            }
        }
Esempio n. 31
0
File: Db.cs Progetto: huizh/xenadmin
            /// <summary>
            /// Initializes a new instance of the <see cref="Table"/> class.
            /// </summary>
            /// <param name="name">The name of the table.</param>
            /// <param name="db">The <see cref="Db"/> to which this <see cref="Table"/> is attached.</param>
            public Table(string name, Db db)
            {
                Util.ThrowIfStringParameterNullOrEmpty(name, "name");
                Util.ThrowIfParameterNull(db, "db");

                _rows = new RowDictionary(this);
                _name = name.ToLower();
                _db = db;
                _xapiType = TypeCache.GetProxyType(name);

                _rows.Changed += delegate { OnChanged(EventArgs.Empty); };
            }
Esempio n. 32
0
        /// <summary>
        /// Assign files to cabinets based on Media authoring.
        /// </summary>
        /// <param name="mediaTable"></param>
        /// <param name="mergeModuleMediaRow"></param>
        /// <param name="fileFacades"></param>
        private void ManuallyAssignFiles(Table mediaTable, MediaRow mergeModuleMediaRow, IEnumerable <FileFacade> fileFacades, Dictionary <MediaRow, List <FileFacade> > filesByCabinetMedia, RowDictionary <MediaRow> mediaRows, List <FileFacade> uncompressedFiles)
        {
            if (OutputType.Module != this.Output.Type)
            {
                if (null != mediaTable)
                {
                    Dictionary <string, MediaRow> cabinetMediaRows = new Dictionary <string, MediaRow>(StringComparer.InvariantCultureIgnoreCase);
                    foreach (MediaRow mediaRow in mediaTable.Rows)
                    {
                        // If the Media row has a cabinet, make sure it is unique across all Media rows.
                        if (!String.IsNullOrEmpty(mediaRow.Cabinet))
                        {
                            MediaRow existingRow;
                            if (cabinetMediaRows.TryGetValue(mediaRow.Cabinet, out existingRow))
                            {
                                Messaging.Instance.OnMessage(WixErrors.DuplicateCabinetName(mediaRow.SourceLineNumbers, mediaRow.Cabinet));
                                Messaging.Instance.OnMessage(WixErrors.DuplicateCabinetName2(existingRow.SourceLineNumbers, existingRow.Cabinet));
                            }
                            else
                            {
                                cabinetMediaRows.Add(mediaRow.Cabinet, mediaRow);
                            }
                        }

                        mediaRows.Add(mediaRow);
                    }
                }

                foreach (MediaRow mediaRow in mediaRows.Values)
                {
                    if (null != mediaRow.Cabinet)
                    {
                        filesByCabinetMedia.Add(mediaRow, new List <FileFacade>());
                    }
                }
            }

            foreach (FileFacade facade in fileFacades)
            {
                if (OutputType.Module == this.Output.Type)
                {
                    filesByCabinetMedia[mergeModuleMediaRow].Add(facade);
                }
                else
                {
                    MediaRow mediaRow;
                    if (!mediaRows.TryGetValue(facade.WixFile.DiskId.ToString(CultureInfo.InvariantCulture), out mediaRow))
                    {
                        Messaging.Instance.OnMessage(WixErrors.MissingMedia(facade.File.SourceLineNumbers, facade.WixFile.DiskId));
                        continue;
                    }

                    // When building a product, if the current file is not to be compressed or if
                    // the package set not to be compressed, don't cab it.
                    if (OutputType.Product == this.Output.Type &&
                        (YesNoType.No == facade.File.Compressed ||
                         (YesNoType.NotSet == facade.File.Compressed && !this.FilesCompressed)))
                    {
                        uncompressedFiles.Add(facade);
                    }
                    else // file is marked compressed.
                    {
                        List <FileFacade> cabinetFiles;
                        if (filesByCabinetMedia.TryGetValue(mediaRow, out cabinetFiles))
                        {
                            cabinetFiles.Add(facade);
                        }
                        else
                        {
                            Messaging.Instance.OnMessage(WixErrors.ExpectedMediaCabinet(facade.File.SourceLineNumbers, facade.File.File, facade.WixFile.DiskId));
                        }
                    }
                }
            }
        }
Esempio n. 33
0
        /// <summary>
        /// Assign files to cabinets based on MediaTemplate authoring.
        /// </summary>
        /// <param name="fileFacades">FileRowCollection</param>
        private void AutoAssignFiles(Table mediaTable, IEnumerable <FileFacade> fileFacades, Dictionary <MediaRow, List <FileFacade> > filesByCabinetMedia, RowDictionary <MediaRow> mediaRows, List <FileFacade> uncompressedFiles)
        {
            const int MaxCabIndex = 999;

            ulong currentPreCabSize = 0;
            ulong maxPreCabSizeInBytes;
            int   maxPreCabSizeInMB = 0;
            int   currentCabIndex   = 0;

            MediaRow currentMediaRow = null;

            Table mediaTemplateTable = this.Output.Tables["WixMediaTemplate"];

            // Auto assign files to cabinets based on maximum uncompressed media size
            mediaTable.Rows.Clear();
            WixMediaTemplateRow mediaTemplateRow = (WixMediaTemplateRow)mediaTemplateTable.Rows[0];

            if (!String.IsNullOrEmpty(mediaTemplateRow.CabinetTemplate))
            {
                this.CabinetNameTemplate = mediaTemplateRow.CabinetTemplate;
            }

            string mumsString = Environment.GetEnvironmentVariable("WIX_MUMS");

            try
            {
                // Override authored mums value if environment variable is authored.
                if (!String.IsNullOrEmpty(mumsString))
                {
                    maxPreCabSizeInMB = Int32.Parse(mumsString);
                }
                else
                {
                    maxPreCabSizeInMB = mediaTemplateRow.MaximumUncompressedMediaSize;
                }

                maxPreCabSizeInBytes = (ulong)maxPreCabSizeInMB * 1024 * 1024;
            }
            catch (FormatException)
            {
                throw new WixException(WixErrors.IllegalEnvironmentVariable("WIX_MUMS", mumsString));
            }
            catch (OverflowException)
            {
                throw new WixException(WixErrors.MaximumUncompressedMediaSizeTooLarge(null, maxPreCabSizeInMB));
            }

            foreach (FileFacade facade in this.FileFacades)
            {
                // When building a product, if the current file is not to be compressed or if
                // the package set not to be compressed, don't cab it.
                if (OutputType.Product == this.Output.Type &&
                    (YesNoType.No == facade.File.Compressed ||
                     (YesNoType.NotSet == facade.File.Compressed && !this.FilesCompressed)))
                {
                    uncompressedFiles.Add(facade);
                    continue;
                }

                if (currentCabIndex == MaxCabIndex)
                {
                    // Associate current file with last cab (irrespective of the size) and cab index is not incremented anymore.
                    List <FileFacade> cabinetFiles = filesByCabinetMedia[currentMediaRow];
                    facade.WixFile.DiskId = currentCabIndex;
                    cabinetFiles.Add(facade);
                    continue;
                }

                // Update current cab size.
                currentPreCabSize += (ulong)facade.File.FileSize;

                if (currentPreCabSize > maxPreCabSizeInBytes)
                {
                    // Overflow due to current file
                    currentMediaRow = this.AddMediaRow(mediaTemplateRow, mediaTable, ++currentCabIndex);
                    mediaRows.Add(currentMediaRow);
                    filesByCabinetMedia.Add(currentMediaRow, new List <FileFacade>());

                    List <FileFacade> cabinetFileRows = filesByCabinetMedia[currentMediaRow];
                    facade.WixFile.DiskId = currentCabIndex;
                    cabinetFileRows.Add(facade);
                    // Now files larger than MaxUncompressedMediaSize will be the only file in its cabinet so as to respect MaxUncompressedMediaSize
                    currentPreCabSize = (ulong)facade.File.FileSize;
                }
                else
                {
                    // File fits in the current cab.
                    if (currentMediaRow == null)
                    {
                        // Create new cab and MediaRow
                        currentMediaRow = this.AddMediaRow(mediaTemplateRow, mediaTable, ++currentCabIndex);
                        mediaRows.Add(currentMediaRow);
                        filesByCabinetMedia.Add(currentMediaRow, new List <FileFacade>());
                    }

                    // Associate current file with current cab.
                    List <FileFacade> cabinetFiles = filesByCabinetMedia[currentMediaRow];
                    facade.WixFile.DiskId = currentCabIndex;
                    cabinetFiles.Add(facade);
                }
            }

            // If there are uncompressed files and no MediaRow, create a default one.
            if (uncompressedFiles.Count > 0 && mediaTable.Rows.Count == 0)
            {
                MediaRow defaultMediaRow = (MediaRow)mediaTable.CreateRow(null);
                defaultMediaRow.DiskId = 1;
                mediaRows.Add(defaultMediaRow);
            }
        }
Esempio n. 34
0
File: Binder.cs Progetto: 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;
        }
        public void Execute()
        {
            Debug.Assert(OutputType.Patch != this.Output.Type);

            var allFileRows = this.CopyOutFileRows ? new List <FileFacade>() : null;

            var copyToPatch   = (allFileRows != null);
            var copyFromPatch = !copyToPatch;

            var patchMediaRows = new RowDictionary <MediaRow>();

            var patchMediaFileRows = new Dictionary <int, RowDictionary <WixFileRow> >();

            var patchActualFileTable = this.Output.EnsureTable(this.TableDefinitions["File"]);
            var patchFileTable       = this.Output.EnsureTable(this.TableDefinitions["WixFile"]);

            if (copyFromPatch)
            {
                // index patch files by diskId+fileId
                foreach (WixFileRow patchFileRow in patchFileTable.Rows)
                {
                    int diskId = patchFileRow.DiskId;
                    if (!patchMediaFileRows.TryGetValue(diskId, out var mediaFileRows))
                    {
                        mediaFileRows = new RowDictionary <WixFileRow>();
                        patchMediaFileRows.Add(diskId, mediaFileRows);
                    }

                    mediaFileRows.Add(patchFileRow);
                }

                var patchMediaTable = this.Output.EnsureTable(this.TableDefinitions["Media"]);
                patchMediaRows = new RowDictionary <MediaRow>(patchMediaTable);
            }

            // Index paired transforms by name without the "#" prefix.
            var pairedTransforms = this.Output.SubStorages.Where(s => s.Name.StartsWith("#")).ToDictionary(s => s.Name.Substring(1), s => s.Data);

            //Dictionary<string, Output> pairedTransforms = new Dictionary<string, Output>();
            //foreach (SubStorage substorage in this.Output.SubStorages)
            //{
            //    if (substorage.Name.StartsWith("#"))
            //    {
            //        pairedTransforms.Add(substorage.Name.Substring(1), substorage.Data);
            //    }
            //}

            try
            {
                // Copy File bind data into substorages
                foreach (var substorage in this.Output.SubStorages)
                {
                    if (substorage.Name.StartsWith("#"))
                    {
                        // no changes necessary for paired transforms
                        continue;
                    }

                    var mainTransform        = substorage.Data;
                    var mainWixFileTable     = mainTransform.Tables["WixFile"];
                    var mainMsiFileHashTable = mainTransform.Tables["MsiFileHash"];

                    this.FileManagerCore.ActiveSubStorage = substorage;

                    var mainWixFiles         = new RowDictionary <WixFileRow>(mainWixFileTable);
                    var mainMsiFileHashIndex = new RowDictionary <Row>();

                    var mainFileTable   = mainTransform.Tables["File"];
                    var pairedTransform = pairedTransforms[substorage.Name];

                    // copy Media.LastSequence and index the MsiFileHash table if it exists.
                    if (copyFromPatch)
                    {
                        var pairedMediaTable = pairedTransform.Tables["Media"];
                        foreach (MediaRow pairedMediaRow in pairedMediaTable.Rows)
                        {
                            var patchMediaRow = patchMediaRows.Get(pairedMediaRow.DiskId);
                            pairedMediaRow.Fields[1] = patchMediaRow.Fields[1];
                        }

                        if (null != mainMsiFileHashTable)
                        {
                            mainMsiFileHashIndex = new RowDictionary <Row>(mainMsiFileHashTable);
                        }

                        // Validate file row changes for keypath-related issues
                        this.ValidateFileRowChanges(mainTransform);
                    }

                    // Index File table of pairedTransform
                    var pairedFileTable = pairedTransform.Tables["File"];
                    var pairedFileRows  = new RowDictionary <FileRow>(pairedFileTable);

                    if (null != mainFileTable)
                    {
                        if (copyFromPatch)
                        {
                            // Remove the MsiFileHash table because it will be updated later with the final file hash for each file
                            mainTransform.Tables.Remove("MsiFileHash");
                        }

                        foreach (FileRow mainFileRow in mainFileTable.Rows)
                        {
                            if (RowOperation.Delete == mainFileRow.Operation)
                            {
                                continue;
                            }
                            else if (RowOperation.None == mainFileRow.Operation && !copyToPatch)
                            {
                                continue;
                            }

                            var mainWixFileRow = mainWixFiles.Get(mainFileRow.File);

                            if (copyToPatch) // when copying to the patch, we need compare the underlying files and include all file changes.
                            {
                                var objectField   = (ObjectField)mainWixFileRow.Fields[6];
                                var pairedFileRow = pairedFileRows.Get(mainFileRow.File);

                                // If the file is new, we always need to add it to the patch.
                                if (mainFileRow.Operation != RowOperation.Add)
                                {
                                    // If PreviousData doesn't exist, target and upgrade layout point to the same location. No need to compare.
                                    if (null == objectField.PreviousData)
                                    {
                                        if (mainFileRow.Operation == RowOperation.None)
                                        {
                                            continue;
                                        }
                                    }
                                    else
                                    {
                                        // TODO: should this entire condition be placed in the binder file manager?
                                        if ((0 == (PatchAttributeType.Ignore & mainWixFileRow.PatchAttributes)) &&
                                            !this.CompareFiles(objectField.PreviousData.ToString(), objectField.Data.ToString()))
                                        {
                                            // If the file is different, we need to mark the mainFileRow and pairedFileRow as modified.
                                            mainFileRow.Operation = RowOperation.Modify;
                                            if (null != pairedFileRow)
                                            {
                                                // Always patch-added, but never non-compressed.
                                                pairedFileRow.Attributes        |= WindowsInstallerConstants.MsidbFileAttributesPatchAdded;
                                                pairedFileRow.Attributes        &= ~WindowsInstallerConstants.MsidbFileAttributesNoncompressed;
                                                pairedFileRow.Fields[6].Modified = true;
                                                pairedFileRow.Operation          = RowOperation.Modify;
                                            }
                                        }
                                        else
                                        {
                                            // The File is same. We need mark all the attributes as unchanged.
                                            mainFileRow.Operation = RowOperation.None;
                                            foreach (var field in mainFileRow.Fields)
                                            {
                                                field.Modified = false;
                                            }

                                            if (null != pairedFileRow)
                                            {
                                                pairedFileRow.Attributes        &= ~WindowsInstallerConstants.MsidbFileAttributesPatchAdded;
                                                pairedFileRow.Fields[6].Modified = false;
                                                pairedFileRow.Operation          = RowOperation.None;
                                            }
                                            continue;
                                        }
                                    }
                                }
                                else if (null != pairedFileRow) // RowOperation.Add
                                {
                                    // Always patch-added, but never non-compressed.
                                    pairedFileRow.Attributes        |= WindowsInstallerConstants.MsidbFileAttributesPatchAdded;
                                    pairedFileRow.Attributes        &= ~WindowsInstallerConstants.MsidbFileAttributesNoncompressed;
                                    pairedFileRow.Fields[6].Modified = true;
                                    pairedFileRow.Operation          = RowOperation.Add;
                                }
                            }

                            // index patch files by diskId+fileId
                            int diskId = mainWixFileRow.DiskId;

                            if (!patchMediaFileRows.TryGetValue(diskId, out var mediaFileRows))
                            {
                                mediaFileRows = new RowDictionary <WixFileRow>();
                                patchMediaFileRows.Add(diskId, mediaFileRows);
                            }

                            var fileId       = mainFileRow.File;
                            var patchFileRow = mediaFileRows.Get(fileId);
                            if (copyToPatch)
                            {
                                if (null == patchFileRow)
                                {
                                    var patchActualFileRow = (FileRow)patchFileTable.CreateRow(mainFileRow.SourceLineNumbers);
                                    patchActualFileRow.CopyFrom(mainFileRow);

                                    patchFileRow = (WixFileRow)patchFileTable.CreateRow(mainFileRow.SourceLineNumbers);
                                    patchFileRow.CopyFrom(mainWixFileRow);

                                    mediaFileRows.Add(patchFileRow);

                                    allFileRows.Add(new FileFacade(patchActualFileRow, patchFileRow, null)); // TODO: should we be passing along delta information? Probably, right?
                                }
                                else
                                {
                                    // TODO: confirm the rest of data is identical?

                                    // make sure Source is same. Otherwise we are silently ignoring a file.
                                    if (0 != String.Compare(patchFileRow.Source, mainWixFileRow.Source, StringComparison.OrdinalIgnoreCase))
                                    {
                                        this.Messaging.Write(ErrorMessages.SameFileIdDifferentSource(mainFileRow.SourceLineNumbers, fileId, patchFileRow.Source, mainWixFileRow.Source));
                                    }

                                    // capture the previous file versions (and associated data) from this targeted instance of the baseline into the current filerow.
                                    patchFileRow.AppendPreviousDataFrom(mainWixFileRow);
                                }
                            }
                            else
                            {
                                // copy data from the patch back to the transform
                                if (null != patchFileRow)
                                {
                                    var pairedFileRow = pairedFileRows.Get(fileId);
                                    for (var i = 0; i < patchFileRow.Fields.Length; i++)
                                    {
                                        var patchValue = patchFileRow[i] == null ? String.Empty : patchFileRow.FieldAsString(i);
                                        var mainValue  = mainFileRow[i] == null ? String.Empty : mainFileRow.FieldAsString(i);

                                        if (1 == i)
                                        {
                                            // File.Component_ changes should not come from the shared file rows
                                            // that contain the file information as each individual transform might
                                            // have different changes (or no changes at all).
                                        }
                                        // File.Attributes should not changed for binary deltas
                                        else if (6 == i)
                                        {
                                            if (null != patchFileRow.Patch)
                                            {
                                                // File.Attribute should not change for binary deltas
                                                pairedFileRow.Attributes       = mainFileRow.Attributes;
                                                mainFileRow.Fields[i].Modified = false;
                                            }
                                        }
                                        // File.Sequence is updated in pairedTransform, not mainTransform
                                        else if (7 == i)
                                        {
                                            // file sequence is updated in Patch table instead of File table for delta patches
                                            if (null != patchFileRow.Patch)
                                            {
                                                pairedFileRow.Fields[i].Modified = false;
                                            }
                                            else
                                            {
                                                pairedFileRow[i] = patchFileRow[i];
                                                pairedFileRow.Fields[i].Modified = true;
                                            }
                                            mainFileRow.Fields[i].Modified = false;
                                        }
                                        else if (patchValue != mainValue)
                                        {
                                            mainFileRow[i] = patchFileRow[i];
                                            mainFileRow.Fields[i].Modified = true;
                                            if (mainFileRow.Operation == RowOperation.None)
                                            {
                                                mainFileRow.Operation = RowOperation.Modify;
                                            }
                                        }
                                    }

                                    // copy MsiFileHash row for this File
                                    if (!mainMsiFileHashIndex.TryGetValue(patchFileRow.File, out var patchHashRow))
                                    {
                                        patchHashRow = patchFileRow.Hash;
                                    }

                                    if (null != patchHashRow)
                                    {
                                        var mainHashTable = mainTransform.EnsureTable(this.TableDefinitions["MsiFileHash"]);
                                        var mainHashRow   = mainHashTable.CreateRow(mainFileRow.SourceLineNumbers);
                                        for (var i = 0; i < patchHashRow.Fields.Length; i++)
                                        {
                                            mainHashRow[i] = patchHashRow[i];
                                            if (i > 1)
                                            {
                                                // assume all hash fields have been modified
                                                mainHashRow.Fields[i].Modified = true;
                                            }
                                        }

                                        // assume the MsiFileHash operation follows the File one
                                        mainHashRow.Operation = mainFileRow.Operation;
                                    }

                                    // copy MsiAssemblyName rows for this File
                                    List <Row> patchAssemblyNameRows = patchFileRow.AssemblyNames;
                                    if (null != patchAssemblyNameRows)
                                    {
                                        var mainAssemblyNameTable = mainTransform.EnsureTable(this.TableDefinitions["MsiAssemblyName"]);
                                        foreach (var patchAssemblyNameRow in patchAssemblyNameRows)
                                        {
                                            // Copy if there isn't an identical modified/added row already in the transform.
                                            var foundMatchingModifiedRow = false;
                                            foreach (var mainAssemblyNameRow in mainAssemblyNameTable.Rows)
                                            {
                                                if (RowOperation.None != mainAssemblyNameRow.Operation && mainAssemblyNameRow.GetPrimaryKey('/').Equals(patchAssemblyNameRow.GetPrimaryKey('/')))
                                                {
                                                    foundMatchingModifiedRow = true;
                                                    break;
                                                }
                                            }

                                            if (!foundMatchingModifiedRow)
                                            {
                                                var mainAssemblyNameRow = mainAssemblyNameTable.CreateRow(mainFileRow.SourceLineNumbers);
                                                for (var i = 0; i < patchAssemblyNameRow.Fields.Length; i++)
                                                {
                                                    mainAssemblyNameRow[i] = patchAssemblyNameRow[i];
                                                }

                                                // assume value field has been modified
                                                mainAssemblyNameRow.Fields[2].Modified = true;
                                                mainAssemblyNameRow.Operation          = mainFileRow.Operation;
                                            }
                                        }
                                    }

                                    // Add patch header for this file
                                    if (null != patchFileRow.Patch)
                                    {
                                        // Add the PatchFiles action automatically to the AdminExecuteSequence and InstallExecuteSequence tables.
                                        this.AddPatchFilesActionToSequenceTable(SequenceTable.AdminExecuteSequence, mainTransform, pairedTransform, mainFileRow);
                                        this.AddPatchFilesActionToSequenceTable(SequenceTable.InstallExecuteSequence, mainTransform, pairedTransform, mainFileRow);

                                        // Add to Patch table
                                        var patchTable = pairedTransform.EnsureTable(this.TableDefinitions["Patch"]);
                                        if (0 == patchTable.Rows.Count)
                                        {
                                            patchTable.Operation = TableOperation.Add;
                                        }

                                        var patchRow = patchTable.CreateRow(mainFileRow.SourceLineNumbers);
                                        patchRow[0] = patchFileRow.File;
                                        patchRow[1] = patchFileRow.Sequence;

                                        var patchFile = new FileInfo(patchFileRow.Source);
                                        patchRow[2] = (int)patchFile.Length;
                                        patchRow[3] = 0 == (PatchAttributeType.AllowIgnoreOnError & patchFileRow.PatchAttributes) ? 0 : 1;

                                        var streamName = patchTable.Name + "." + patchRow[0] + "." + patchRow[1];
                                        if (Msi.MsiInterop.MsiMaxStreamNameLength < streamName.Length)
                                        {
                                            streamName = "_" + Guid.NewGuid().ToString("D").ToUpperInvariant().Replace('-', '_');

                                            var patchHeadersTable = pairedTransform.EnsureTable(this.TableDefinitions["MsiPatchHeaders"]);
                                            if (0 == patchHeadersTable.Rows.Count)
                                            {
                                                patchHeadersTable.Operation = TableOperation.Add;
                                            }

                                            var patchHeadersRow = patchHeadersTable.CreateRow(mainFileRow.SourceLineNumbers);
                                            patchHeadersRow[0]        = streamName;
                                            patchHeadersRow[1]        = patchFileRow.Patch;
                                            patchRow[5]               = streamName;
                                            patchHeadersRow.Operation = RowOperation.Add;
                                        }
                                        else
                                        {
                                            patchRow[4] = patchFileRow.Patch;
                                        }
                                        patchRow.Operation = RowOperation.Add;
                                    }
                                }
                                else
                                {
                                    // TODO: throw because all transform rows should have made it into the patch
                                }
                            }
                        }
                    }

                    if (copyFromPatch)
                    {
                        this.Output.Tables.Remove("Media");
                        this.Output.Tables.Remove("File");
                        this.Output.Tables.Remove("MsiFileHash");
                        this.Output.Tables.Remove("MsiAssemblyName");
                    }
                }
            }
            finally
            {
                this.FileManagerCore.ActiveSubStorage = null;
            }

            this.FileFacades = allFileRows;
        }