示例#1
0
        private static IList <SoftwareTag> CollectPackageTags(Output bundle)
        {
            List <SoftwareTag> tags = new List <SoftwareTag>();
            Table packageTable      = bundle.Tables["WixBundlePackage"];

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

                foreach (WixBundlePackageRow row in packageTable.RowsAs <WixBundlePackageRow>())
                {
                    if (WixBundlePackageType.Msi == row.Type)
                    {
                        string packagePayloadId     = row.PackagePayload;
                        WixBundlePayloadRow payload = payloads.Get(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);
        }
示例#2
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));
                }
            }
        }
示例#3
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;
        }
        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;
        }
        public void Execute()
        {
            var allFileRows = new List <IFileFacade>();

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

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

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

            // Enumerate through main transforms.
            foreach (var substorage in this.SubStorages.Where(s => !s.Name.StartsWith("#")))
            {
                var mainTransform = substorage.Data;
                var mainFileTable = mainTransform.Tables["File"];

                if (null == mainFileTable)
                {
                    continue;
                }

                // Index File table of pairedTransform
                var pairedTransform = pairedTransforms["#" + substorage.Name];
                var pairedFileRows  = new RowDictionary <FileRow>(pairedTransform.Tables["File"]);

                foreach (FileRow mainFileRow in mainFileTable.Rows.Where(f => f.Operation != RowOperation.Delete))
                {
                    var mainFileId = mainFileRow.File;

                    // We need compare the underlying files and include all file changes.
                    var objectField   = (ObjectField)mainFileRow.Fields[9];
                    var pairedFileRow = pairedFileRows.Get(mainFileId);

                    // If the file is new, we always need to add it to the patch.
                    if (mainFileRow.Operation == RowOperation.Add)
                    {
                        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;
                        }
                    }
                    else
                    {
                        // 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.FileSystemManager.CompareFiles(objectField.PreviousData, 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;
                            }
                        }
                    }

                    // index patch files by diskId+fileId
                    var diskId = mainFileRow.DiskId;

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

                    var patchFileRow = mediaFileRows.Get(mainFileId);

                    if (null == patchFileRow)
                    {
                        //patchFileRow = (FileRow)patchFileTable.CreateRow(mainFileRow.SourceLineNumbers);
                        patchFileRow = (FileRow)mainFileRow.TableDefinition.CreateRow(mainFileRow.SourceLineNumbers);
                        mainFileRow.CopyTo(patchFileRow);

                        mediaFileRows.Add(patchFileRow);

#if TODO_PATCHING_DELTA
                        // TODO: should we be passing along delta information to the file facade? Probably, right?
#endif
                        var fileFacade = this.BackendHelper.CreateFileFacade(patchFileRow);

                        allFileRows.Add(fileFacade);
                    }
                    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, mainFileRow.Source, StringComparison.OrdinalIgnoreCase))
                        {
                            this.Messaging.Write(ErrorMessages.SameFileIdDifferentSource(mainFileRow.SourceLineNumbers, mainFileId, patchFileRow.Source, mainFileRow.Source));
                        }

#if TODO_PATCHING_DELTA
                        // capture the previous file versions (and associated data) from this targeted instance of the baseline into the current filerow.
                        patchFileRow.AppendPreviousDataFrom(mainFileRow);
#endif
                    }
                }
            }

            this.FileFacades = allFileRows;
        }
示例#6
0
        public void Execute()
        {
            throw new NotImplementedException();
#if TODO
            this.FileTransfers    = Enumerable.Empty <FileTransfer>();
            this.ContentFilePaths = Enumerable.Empty <string>();

            // First look for data we expect to find... Chain, WixGroups, etc.

            // 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!
            Table chainPackageTable = this.GetRequiredTable("WixBundlePackage");

            Table wixGroupTable = this.GetRequiredTable("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.
            WixBundleRow bundleRow = (WixBundleRow)this.GetSingleRowTable("WixBundle");

            bundleRow.PerMachine = true; // default to per-machine but the first-per user package wil flip the bundle per-user.

            // Ensure there is one and only one row in the WixBootstrapperApplication table.
            // The compiler and linker behavior should have colluded to get
            // this behavior.
            Row baRow = this.GetSingleRowTable("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.
            WixChainRow chainRow = (WixChainRow)this.GetSingleRowTable("WixChain");

            if (Messaging.Instance.EncounteredError)
            {
                return;
            }

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

            // 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.
            IEnumerable <WixSearchInfo> orderedSearches = this.OrderSearches();

            // Extract files that come from cabinet files (this does not extract files from merge modules).
            {
                var extractEmbeddedFilesCommand = new ExtractEmbeddedFilesCommand();
                extractEmbeddedFilesCommand.FilesWithEmbeddedFiles = ExpectedEmbeddedFiles;
                extractEmbeddedFilesCommand.Execute();
            }

            // Get the explicit payloads.
            RowDictionary <WixBundlePayloadRow> payloads = new RowDictionary <WixBundlePayloadRow>(this.Output.Tables["WixBundlePayload"]);

            // Update explicitly authored payloads with their parent package and container (as appropriate)
            // to make it easier to gather the payloads later.
            foreach (WixGroupRow row in wixGroupTable.RowsAs <WixGroupRow>())
            {
                if (ComplexReferenceChildType.Payload == row.ChildType)
                {
                    WixBundlePayloadRow payload = payloads.Get(row.ChildId);

                    if (ComplexReferenceParentType.Package == row.ParentType)
                    {
                        Debug.Assert(String.IsNullOrEmpty(payload.Package));
                        payload.Package = row.ParentId;
                    }
                    else if (ComplexReferenceParentType.Container == row.ParentType)
                    {
                        Debug.Assert(String.IsNullOrEmpty(payload.Container));
                        payload.Container = row.ParentId;
                    }
                    else if (ComplexReferenceParentType.Layout == row.ParentType)
                    {
                        payload.LayoutOnly = true;
                    }
                }
            }

            List <FileTransfer> fileTransfers = new List <FileTransfer>();
            string layoutDirectory            = Path.GetDirectoryName(this.OutputPath);

            // Process the explicitly authored payloads.
            ISet <string> processedPayloads;
            {
                ProcessPayloadsCommand command = new ProcessPayloadsCommand();
                command.Payloads         = payloads.Values;
                command.DefaultPackaging = bundleRow.DefaultPackagingType;
                command.LayoutDirectory  = layoutDirectory;
                command.Execute();

                fileTransfers.AddRange(command.FileTransfers);

                processedPayloads = new HashSet <string>(payloads.Keys);
            }

            IDictionary <string, PackageFacade> facades;
            {
                GetPackageFacadesCommand command = new GetPackageFacadesCommand();
                command.PackageTable    = chainPackageTable;
                command.ExePackageTable = this.Output.Tables["WixBundleExePackage"];
                command.MsiPackageTable = this.Output.Tables["WixBundleMsiPackage"];
                command.MspPackageTable = this.Output.Tables["WixBundleMspPackage"];
                command.MsuPackageTable = this.Output.Tables["WixBundleMsuPackage"];
                command.Execute();

                facades = command.PackageFacades;
            }

            // Process each package facade. Note this is likely to add payloads and other rows to tables so
            // note that any indexes created above may be out of date now.
            foreach (PackageFacade facade in facades.Values)
            {
                switch (facade.Package.Type)
                {
                case WixBundlePackageType.Exe:
                {
                    ProcessExePackageCommand command = new ProcessExePackageCommand();
                    command.AuthoredPayloads = payloads;
                    command.Facade           = facade;
                    command.Execute();

                    // ? variableCache.Add(String.Concat("packageManufacturer.", facade.Package.WixChainItemId), facade.ExePackage.Manufacturer);
                }
                break;

                case WixBundlePackageType.Msi:
                {
                    var command = new ProcessMsiPackageCommand();
                    command.AuthoredPayloads    = payloads;
                    command.Facade              = facade;
                    command.BackendExtensions   = this.BackendExtensions;
                    command.MsiFeatureTable     = this.Output.EnsureTable(this.TableDefinitions["WixBundleMsiFeature"]);
                    command.MsiPropertyTable    = this.Output.EnsureTable(this.TableDefinitions["WixBundleMsiProperty"]);
                    command.PayloadTable        = this.Output.Tables["WixBundlePayload"];
                    command.RelatedPackageTable = this.Output.EnsureTable(this.TableDefinitions["WixBundleRelatedPackage"]);
                    command.Execute();

                    if (null != variableCache)
                    {
                        variableCache.Add(String.Concat("packageLanguage.", facade.Package.WixChainItemId), facade.MsiPackage.ProductLanguage.ToString());

                        if (null != facade.MsiPackage.Manufacturer)
                        {
                            variableCache.Add(String.Concat("packageManufacturer.", facade.Package.WixChainItemId), facade.MsiPackage.Manufacturer);
                        }
                    }
                }
                break;

                case WixBundlePackageType.Msp:
                {
                    ProcessMspPackageCommand command = new ProcessMspPackageCommand();
                    command.AuthoredPayloads = payloads;
                    command.Facade           = facade;
                    command.WixBundlePatchTargetCodeTable = this.Output.EnsureTable(this.TableDefinitions["WixBundlePatchTargetCode"]);
                    command.Execute();
                }
                break;

                case WixBundlePackageType.Msu:
                {
                    ProcessMsuPackageCommand command = new ProcessMsuPackageCommand();
                    command.Facade = facade;
                    command.Execute();
                }
                break;
                }

                if (null != variableCache)
                {
                    BindBundleCommand.PopulatePackageVariableCache(facade.Package, variableCache);
                }
            }

            // Reindex the payloads now that all the payloads (minus the manifest payloads that will be created later)
            // are present.
            payloads = new RowDictionary <WixBundlePayloadRow>(this.Output.Tables["WixBundlePayload"]);

            // Process the payloads that were added by processing the packages.
            {
                ProcessPayloadsCommand command = new ProcessPayloadsCommand();
                command.Payloads         = payloads.Values.Where(r => !processedPayloads.Contains(r.Id)).ToList();
                command.DefaultPackaging = bundleRow.DefaultPackagingType;
                command.LayoutDirectory  = layoutDirectory;
                command.Execute();

                fileTransfers.AddRange(command.FileTransfers);

                processedPayloads = null;
            }

            // Set the package metadata from the payloads now that we have the complete payload information.
            ILookup <string, WixBundlePayloadRow> payloadsByPackage = payloads.Values.ToLookup(p => p.Package);

            {
                foreach (PackageFacade facade in facades.Values)
                {
                    facade.Package.Size = 0;

                    IEnumerable <WixBundlePayloadRow> packagePayloads = payloadsByPackage[facade.Package.WixChainItemId];

                    foreach (WixBundlePayloadRow payload in packagePayloads)
                    {
                        facade.Package.Size += payload.FileSize;
                    }

                    if (!facade.Package.InstallSize.HasValue)
                    {
                        facade.Package.InstallSize = facade.Package.Size;
                    }

                    WixBundlePayloadRow packagePayload = payloads[facade.Package.PackagePayload];

                    if (String.IsNullOrEmpty(facade.Package.Description))
                    {
                        facade.Package.Description = packagePayload.Description;
                    }

                    if (String.IsNullOrEmpty(facade.Package.DisplayName))
                    {
                        facade.Package.DisplayName = packagePayload.DisplayName;
                    }
                }
            }


            // Give the UX payloads their embedded IDs...
            int uxPayloadIndex = 0;
            {
                foreach (WixBundlePayloadRow payload in payloads.Values.Where(p => Compiler.BurnUXContainerId == p.Container))
                {
                    // 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)
                    {
                        Messaging.Instance.OnMessage(WixWarnings.UxPayloadsOnlySupportEmbedding(payload.SourceLineNumbers, payload.FullFileName));
                        payload.Packaging = PackagingType.Embedded;
                    }

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

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

                // Give the embedded payloads without an embedded id yet an embedded id.
                int payloadIndex = 0;
                foreach (WixBundlePayloadRow payload in payloads.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;
                    }
                }
            }

            // Determine patches to automatically slipstream.
            {
                AutomaticallySlipstreamPatchesCommand command = new AutomaticallySlipstreamPatchesCommand();
                command.PackageFacades                = facades.Values;
                command.SlipstreamMspTable            = this.Output.EnsureTable(this.TableDefinitions["WixBundleSlipstreamMsp"]);
                command.WixBundlePatchTargetCodeTable = this.Output.EnsureTable(this.TableDefinitions["WixBundlePatchTargetCode"]);
                command.Execute();
            }

            // If catalog files exist, non-embedded payloads should validate with the catalogs.
            IEnumerable <WixBundleCatalogRow> catalogs = this.Output.Tables["WixBundleCatalog"].RowsAs <WixBundleCatalogRow>();

            if (catalogs.Any())
            {
                VerifyPayloadsWithCatalogCommand command = new VerifyPayloadsWithCatalogCommand();
                command.Catalogs = catalogs;
                command.Payloads = payloads.Values;
                command.Execute();
            }

            if (Messaging.Instance.EncounteredError)
            {
                return;
            }

            IEnumerable <PackageFacade> orderedFacades;
            IEnumerable <WixBundleRollbackBoundaryRow> boundaries;
            {
                OrderPackagesAndRollbackBoundariesCommand command = new OrderPackagesAndRollbackBoundariesCommand();
                command.Boundaries     = new RowDictionary <WixBundleRollbackBoundaryRow>(this.Output.Tables["WixBundleRollbackBoundary"]);
                command.PackageFacades = facades;
                command.WixGroupTable  = wixGroupTable;
                command.Execute();

                orderedFacades = command.OrderedPackageFacades;
                boundaries     = command.UsedRollbackBoundaries;
            }

            // Resolve any delayed fields before generating the manifest.
            if (this.DelayedFields.Any())
            {
                var resolveDelayedFieldsCommand = new ResolveDelayedFieldsCommand();
                resolveDelayedFieldsCommand.OutputType         = this.Output.Type;
                resolveDelayedFieldsCommand.DelayedFields      = this.DelayedFields;
                resolveDelayedFieldsCommand.ModularizationGuid = null;
                resolveDelayedFieldsCommand.VariableCache      = variableCache;
                resolveDelayedFieldsCommand.Execute();
            }

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

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

            // Update the bundle per-machine/per-user scope based on the chained packages.
            this.ResolveBundleInstallScope(bundleRow, orderedFacades);

            // Generate the core-defined BA manifest tables...
            {
                CreateBootstrapperApplicationManifestCommand command = new CreateBootstrapperApplicationManifestCommand();
                command.BundleRow          = bundleRow;
                command.ChainPackages      = orderedFacades;
                command.LastUXPayloadIndex = uxPayloadIndex;
                command.MsiFeatures        = this.Output.Tables["WixBundleMsiFeature"].RowsAs <WixBundleMsiFeatureRow>();
                command.Output             = this.Output;
                command.Payloads           = payloads;
                command.TableDefinitions   = this.TableDefinitions;
                command.TempFilesLocation  = this.IntermediateFolder;
                command.Execute();

                WixBundlePayloadRow baManifestPayload = command.BootstrapperApplicationManifestPayloadRow;
                payloads.Add(baManifestPayload);
            }

            //foreach (BinderExtension extension in this.Extensions)
            //{
            //    extension.PostBind(this.Context);
            //}

            // Create all the containers except the UX container first so the manifest (that goes in the UX container)
            // can contain all size and hash information about the non-UX containers.
            RowDictionary <WixBundleContainerRow> containers = new RowDictionary <WixBundleContainerRow>(this.Output.Tables["WixBundleContainer"]);

            ILookup <string, WixBundlePayloadRow> payloadsByContainer = payloads.Values.ToLookup(p => p.Container);

            int attachedContainerIndex = 1; // count starts at one because UX container is "0".

            IEnumerable <WixBundlePayloadRow> uxContainerPayloads = Enumerable.Empty <WixBundlePayloadRow>();

            foreach (WixBundleContainerRow container in containers.Values)
            {
                IEnumerable <WixBundlePayloadRow> containerPayloads = payloadsByContainer[container.Id];

                if (!containerPayloads.Any())
                {
                    if (container.Id != Compiler.BurnDefaultAttachedContainerId)
                    {
                        // TODO: display warning that we're ignoring container that ended up with no paylods in it.
                    }
                }
                else if (Compiler.BurnUXContainerId == container.Id)
                {
                    container.WorkingPath            = Path.Combine(this.IntermediateFolder, container.Name);
                    container.AttachedContainerIndex = 0;

                    // Gather the list of UX payloads but ensure the BootstrapperApplication Payload is the first
                    // in the list since that is the Payload that Burn attempts to load.
                    List <WixBundlePayloadRow> uxPayloads = new List <WixBundlePayloadRow>();

                    string baPayloadId = baRow.FieldAsString(0);

                    foreach (WixBundlePayloadRow uxPayload in containerPayloads)
                    {
                        if (uxPayload.Id == baPayloadId)
                        {
                            uxPayloads.Insert(0, uxPayload);
                        }
                        else
                        {
                            uxPayloads.Add(uxPayload);
                        }
                    }

                    uxContainerPayloads = uxPayloads;
                }
                else
                {
                    container.WorkingPath = Path.Combine(this.IntermediateFolder, container.Name);

                    // Add detached containers to the list of file transfers.
                    if (ContainerType.Detached == container.Type)
                    {
                        FileTransfer transfer;
                        if (FileTransfer.TryCreate(container.WorkingPath, Path.Combine(layoutDirectory, container.Name), true, "Container", container.SourceLineNumbers, out transfer))
                        {
                            transfer.Built = true;
                            fileTransfers.Add(transfer);
                        }
                    }
                    else // update the attached container index.
                    {
                        Debug.Assert(ContainerType.Attached == container.Type);

                        container.AttachedContainerIndex = attachedContainerIndex;
                        ++attachedContainerIndex;
                    }

                    this.CreateContainer(container, containerPayloads, null);
                }
            }

            // Create the bundle manifest then UX container.
            string manifestPath = Path.Combine(this.IntermediateFolder, "bundle-manifest.xml");
            {
                var command = new CreateBurnManifestCommand();
                command.BackendExtensions = this.BackendExtensions;
                command.Output            = this.Output;

                command.BundleInfo          = bundleRow;
                command.Chain               = chainRow;
                command.Containers          = containers;
                command.Catalogs            = catalogs;
                command.ExecutableName      = Path.GetFileName(this.OutputPath);
                command.OrderedPackages     = orderedFacades;
                command.OutputPath          = manifestPath;
                command.RollbackBoundaries  = boundaries;
                command.OrderedSearches     = orderedSearches;
                command.Payloads            = payloads;
                command.UXContainerPayloads = uxContainerPayloads;
                command.Execute();
            }

            WixBundleContainerRow uxContainer = containers[Compiler.BurnUXContainerId];
            this.CreateContainer(uxContainer, uxContainerPayloads, manifestPath);

            // Copy the burn.exe to a writable location then mark it to be moved to its final build location. Note
            // that today, the x64 Burn uses the x86 stub.
            string stubPlatform = (Platform.X64 == bundleRow.Platform) ? "x86" : bundleRow.Platform.ToString();

            string stubFile       = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), stubPlatform, "burn.exe");
            string bundleTempPath = Path.Combine(this.IntermediateFolder, Path.GetFileName(this.OutputPath));

            Messaging.Instance.OnMessage(WixVerboses.GeneratingBundle(bundleTempPath, stubFile));

            string bundleFilename = Path.GetFileName(this.OutputPath);
            if ("setup.exe".Equals(bundleFilename, StringComparison.OrdinalIgnoreCase))
            {
                Messaging.Instance.OnMessage(WixErrors.InsecureBundleFilename(bundleFilename));
            }

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

            File.Copy(stubFile, bundleTempPath, true);
            File.SetAttributes(bundleTempPath, FileAttributes.Normal);

            this.UpdateBurnResources(bundleTempPath, this.OutputPath, bundleRow);

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

                // Always attach the UX container first
                writer.AppendContainer(uxContainer.WorkingPath, BurnWriter.Container.UX);

                // Now append all other attached containers
                foreach (WixBundleContainerRow container in containers.Values)
                {
                    if (ContainerType.Attached == container.Type)
                    {
                        // The container was only created if it had payloads.
                        if (!String.IsNullOrEmpty(container.WorkingPath) && Compiler.BurnUXContainerId != container.Id)
                        {
                            writer.AppendContainer(container.WorkingPath, BurnWriter.Container.Attached);
                        }
                    }
                }
            }

            if (null != this.PdbFile)
            {
                Pdb pdb = new Pdb();
                pdb.Output = Output;
                pdb.Save(this.PdbFile);
            }

            this.FileTransfers    = fileTransfers;
            this.ContentFilePaths = payloads.Values.Where(p => p.ContentFile).Select(p => p.FullFileName).ToList();
        }
示例#7
0
        public void Execute()
        {
            var fileFacadesByDiskId = new Dictionary <int, Dictionary <string, FileFacade> >();

            // Index patch file facades by diskId+fileId.
            foreach (var facade in this.FileFacades)
            {
                if (!fileFacadesByDiskId.TryGetValue(facade.DiskId, out var mediaFacades))
                {
                    mediaFacades = new Dictionary <string, FileFacade>();
                    fileFacadesByDiskId.Add(facade.DiskId, mediaFacades);
                }

                mediaFacades.Add(facade.Id, facade);
            }

            var patchMediaRows = new RowDictionary <MediaRow>(this.Output.Tables["Media"]);

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

            // Copy File bind data into substorages
            foreach (var substorage in this.SubStorages.Where(s => !s.Name.StartsWith("#")))
            {
                var mainTransform = substorage.Data;

                var mainMsiFileHashIndex = new RowDictionary <Row>(mainTransform.Tables["MsiFileHash"]);

                var pairedTransform = pairedTransforms["#" + substorage.Name];

                // Copy Media.LastSequence.
                var pairedMediaTable = pairedTransform.Tables["Media"];
                foreach (MediaRow pairedMediaRow in pairedMediaTable.Rows)
                {
                    var patchMediaRow = patchMediaRows.Get(pairedMediaRow.DiskId);
                    pairedMediaRow.LastSequence = patchMediaRow.LastSequence;
                }

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

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

                var mainFileTable = mainTransform.Tables["File"];
                if (null != mainFileTable)
                {
                    // 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)
                        {
                            continue;
                        }

                        // Index patch files by diskId+fileId
                        if (!fileFacadesByDiskId.TryGetValue(mainFileRow.DiskId, out var mediaFacades))
                        {
                            mediaFacades = new Dictionary <string, FileFacade>();
                            fileFacadesByDiskId.Add(mainFileRow.DiskId, mediaFacades);
                        }

                        // copy data from the patch back to the transform
                        if (mediaFacades.TryGetValue(mainFileRow.File, out var facade))
                        {
                            var patchFileRow  = facade.GetFileRow();
                            var pairedFileRow = pairedFileRows.Get(mainFileRow.File);

                            for (var i = 0; i < patchFileRow.Fields.Length; i++)
                            {
                                var patchValue = patchFileRow.FieldAsString(i) ?? String.Empty;
                                var mainValue  = mainFileRow.FieldAsString(i) ?? String.Empty;

                                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).
                                }
                                else if (6 == i) // File.Attributes should not changed for binary deltas
                                {
#if TODO_PATCHING_DELTA
                                    if (null != patchFileRow.Patch)
                                    {
                                        // File.Attribute should not change for binary deltas
                                        pairedFileRow.Attributes       = mainFileRow.Attributes;
                                        mainFileRow.Fields[i].Modified = false;
                                    }
#endif
                                }
                                else if (7 == i) // File.Sequence is updated in pairedTransform, not mainTransform
                                {
                                    // file sequence is updated in Patch table instead of File table for delta patches
#if TODO_PATCHING_DELTA
                                    if (null != patchFileRow.Patch)
                                    {
                                        pairedFileRow.Fields[i].Modified = false;
                                    }
                                    else
#endif
                                    {
                                        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;
                                throw new NotImplementedException();
                            }

                            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
#if TODO_PATCHING
                            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;
                                    }
                                }
                            }
#endif

                            // Add patch header for this file
#if TODO_PATCHING_DELTA
                            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;
                            }
#endif
                        }
                        else
                        {
                            // TODO: throw because all transform rows should have made it into the patch
                        }
                    }
                }

                this.Output.Tables.Remove("Media");
                this.Output.Tables.Remove("File");
                this.Output.Tables.Remove("MsiFileHash");
                this.Output.Tables.Remove("MsiAssemblyName");
            }
        }
示例#8
0
        public void Execute()
        {
            var fileRows  = new RowDictionary <FileRow>(this.Output.Tables["File"]);
            var mediaRows = new RowDictionary <MediaRow>(this.Output.Tables["Media"]);

            // Calculate sequence numbers and media disk id layout for all file media information objects.
            if (OutputType.Module == this.Output.Type)
            {
                var lastSequence = 0;

                // Order by Component to group the files by directory.
                var optimized = this.OptimizedFileFacades();
                foreach (var fileId in optimized.Select(f => f.File.File))
                {
                    var fileRow = fileRows.Get(fileId);
                    fileRow.Sequence = ++lastSequence;
                }
            }
            else
            {
                int      lastSequence = 0;
                MediaRow mediaRow     = null;
                Dictionary <int, List <FileFacade> > patchGroups = new Dictionary <int, List <FileFacade> >();

                // sequence the non-patch-added files
                var optimized = this.OptimizedFileFacades();
                foreach (FileFacade facade in optimized)
                {
                    if (null == mediaRow)
                    {
                        mediaRow = mediaRows.Get(facade.WixFile.DiskId);
                        if (OutputType.Patch == this.Output.Type)
                        {
                            // patch Media cannot start at zero
                            lastSequence = mediaRow.LastSequence;
                        }
                    }
                    else if (mediaRow.DiskId != facade.WixFile.DiskId)
                    {
                        mediaRow.LastSequence = lastSequence;
                        mediaRow = mediaRows.Get(facade.WixFile.DiskId);
                    }

                    if (0 < facade.WixFile.PatchGroup)
                    {
                        if (patchGroups.TryGetValue(facade.WixFile.PatchGroup, out var patchGroup))
                        {
                            patchGroup = new List <FileFacade>();
                            patchGroups.Add(facade.WixFile.PatchGroup, patchGroup);
                        }

                        patchGroup.Add(facade);
                    }
                    else
                    {
                        var fileRow = fileRows.Get(facade.File.File);
                        fileRow.Sequence = ++lastSequence;
                    }
                }

                if (null != mediaRow)
                {
                    mediaRow.LastSequence = lastSequence;
                    mediaRow = null;
                }

                // sequence the patch-added files
                foreach (var patchGroup in patchGroups.Values)
                {
                    foreach (var facade in patchGroup)
                    {
                        if (null == mediaRow)
                        {
                            mediaRow = mediaRows.Get(facade.WixFile.DiskId);
                        }
                        else if (mediaRow.DiskId != facade.WixFile.DiskId)
                        {
                            mediaRow.LastSequence = lastSequence;
                            mediaRow = mediaRows.Get(facade.WixFile.DiskId);
                        }

                        var fileRow = fileRows.Get(facade.File.File);
                        fileRow.Sequence = ++lastSequence;
                    }
                }

                if (null != mediaRow)
                {
                    mediaRow.LastSequence = lastSequence;
                }
            }
        }