示例#1
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;
            }
        }
示例#2
0
        /// <summary>
        /// Adds a row to the media table with cab name template filled in.
        /// </summary>
        /// <param name="mediaTable"></param>
        /// <param name="cabIndex"></param>
        /// <returns></returns>
        private MediaRow AddMediaRow(WixMediaTemplateRow mediaTemplateRow, Table mediaTable, int cabIndex)
        {
            MediaRow currentMediaRow = (MediaRow)mediaTable.CreateRow(mediaTemplateRow.SourceLineNumbers);

            currentMediaRow.DiskId  = cabIndex;
            currentMediaRow.Cabinet = String.Format(CultureInfo.InvariantCulture, this.CabinetNameTemplate, cabIndex);

            Table       wixMediaTable = this.Output.EnsureTable(this.TableDefinitions["WixMedia"]);
            WixMediaRow row           = (WixMediaRow)wixMediaTable.CreateRow(mediaTemplateRow.SourceLineNumbers);

            row.DiskId           = cabIndex;
            row.CompressionLevel = mediaTemplateRow.CompressionLevel;

            return(currentMediaRow);
        }
示例#3
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;
        }
示例#4
0
        /// <summary>
        /// Call back to Add File Transfer for new Cab and add new Cab to Media table
        /// This callback can come from Multiple Cabinet Builder Threads and so should be thread safe
        /// This callback will not be called in case there is no File splitting. i.e. MaximumCabinetSizeForLargeFileSplitting was not authored
        /// </summary>
        /// <param name="firstCabName">The name of splitting cabinet without extention e.g. "cab1".</param>
        /// <param name="newCabName">The name of the new cabinet that would be formed by splitting e.g. "cab1b.cab"</param>
        /// <param name="fileToken">The file token of the first file present in the splitting cabinet</param>
        internal void NewCabNamesCallBack([MarshalAs(UnmanagedType.LPWStr)] string firstCabName, [MarshalAs(UnmanagedType.LPWStr)] string newCabName, [MarshalAs(UnmanagedType.LPWStr)] string fileToken)
        {
            // Locking Mutex here as this callback can come from Multiple Cabinet Builder Threads
            Mutex mutex = new Mutex(false, "WixCabinetSplitBinderCallback");

            try
            {
                if (!mutex.WaitOne(0, false)) // Check if you can get the lock
                {
                    // Cound not get the Lock
                    Messaging.Instance.OnMessage(WixVerboses.CabinetsSplitInParallel());
                    mutex.WaitOne(); // Wait on other thread
                }

                string firstCabinetName = firstCabName + ".cab";
                string newCabinetName   = newCabName;
                bool   transferAdded    = false; // Used for Error Handling

                // Create File Transfer for new Cabinet using transfer of Base Cabinet
                foreach (FileTransfer transfer in this.FileTransfers)
                {
                    if (firstCabinetName.Equals(Path.GetFileName(transfer.Source), StringComparison.InvariantCultureIgnoreCase))
                    {
                        string newCabSourcePath = Path.Combine(Path.GetDirectoryName(transfer.Source), newCabinetName);
                        string newCabTargetPath = Path.Combine(Path.GetDirectoryName(transfer.Destination), newCabinetName);

                        FileTransfer newTransfer;
                        if (FileTransfer.TryCreate(newCabSourcePath, newCabTargetPath, transfer.Move, "Cabinet", transfer.SourceLineNumbers, out newTransfer))
                        {
                            newTransfer.Built = true;
                            this.fileTransfers.Add(newTransfer);
                            transferAdded = true;
                            break;
                        }
                    }
                }

                // Check if File Transfer was added
                if (!transferAdded)
                {
                    throw new WixException(WixErrors.SplitCabinetCopyRegistrationFailed(newCabinetName, firstCabinetName));
                }

                // Add the new Cabinets to media table using LastSequence of Base Cabinet
                Table mediaTable   = this.Output.Tables["Media"];
                Table wixFileTable = this.Output.Tables["WixFile"];
                int   diskIDForLastSplitCabAdded       = 0;     // The DiskID value for the first cab in this cabinet split chain
                int   lastSequenceForLastSplitCabAdded = 0;     // The LastSequence value for the first cab in this cabinet split chain
                bool  lastSplitCabinetFound            = false; // Used for Error Handling

                string lastCabinetOfThisSequence = String.Empty;
                // Get the Value of Last Cabinet Added in this split Sequence from Dictionary
                if (!this.lastCabinetAddedToMediaTable.TryGetValue(firstCabinetName, out lastCabinetOfThisSequence))
                {
                    // If there is no value for this sequence, then use first Cabinet is the last one of this split sequence
                    lastCabinetOfThisSequence = firstCabinetName;
                }

                foreach (MediaRow mediaRow in mediaTable.Rows)
                {
                    // Get details for the Last Cabinet Added in this Split Sequence
                    if ((lastSequenceForLastSplitCabAdded == 0) && lastCabinetOfThisSequence.Equals(mediaRow.Cabinet, StringComparison.InvariantCultureIgnoreCase))
                    {
                        lastSequenceForLastSplitCabAdded = mediaRow.LastSequence;
                        diskIDForLastSplitCabAdded       = mediaRow.DiskId;
                        lastSplitCabinetFound            = true;
                    }

                    // Check for Name Collision for the new Cabinet added
                    if (newCabinetName.Equals(mediaRow.Cabinet, StringComparison.InvariantCultureIgnoreCase))
                    {
                        // Name Collision of generated Split Cabinet Name and user Specified Cab name for current row
                        throw new WixException(WixErrors.SplitCabinetNameCollision(newCabinetName, firstCabinetName));
                    }
                }

                // Check if the last Split Cabinet was found in the Media Table
                if (!lastSplitCabinetFound)
                {
                    throw new WixException(WixErrors.SplitCabinetInsertionFailed(newCabinetName, firstCabinetName, lastCabinetOfThisSequence));
                }

                // The new Row has to be inserted just after the last cab in this cabinet split chain according to DiskID Sort
                // This is because the FDI Extract requires DiskID of Split Cabinets to be continuous. It Fails otherwise with
                // Error 2350 (FDI Server Error) as next DiskID did not have the right split cabinet during extraction
                MediaRow newMediaRow = (MediaRow)mediaTable.CreateRow(null);
                newMediaRow.Cabinet      = newCabinetName;
                newMediaRow.DiskId       = diskIDForLastSplitCabAdded + 1; // When Sorted with DiskID, this new Cabinet Row is an Insertion
                newMediaRow.LastSequence = lastSequenceForLastSplitCabAdded;

                // Now increment the DiskID for all rows that come after the newly inserted row to Ensure that DiskId is unique
                foreach (MediaRow mediaRow in mediaTable.Rows)
                {
                    // Check if this row comes after inserted row and it is not the new cabinet inserted row
                    if (mediaRow.DiskId >= newMediaRow.DiskId && !newCabinetName.Equals(mediaRow.Cabinet, StringComparison.InvariantCultureIgnoreCase))
                    {
                        mediaRow.DiskId++; // Increment DiskID
                    }
                }

                // Now Increment DiskID for All files Rows so that they refer to the right Media Row
                foreach (WixFileRow wixFileRow in wixFileTable.Rows)
                {
                    // Check if this row comes after inserted row and if this row is not the file that has to go into the current cabinet
                    // This check will work as we have only one large file in every splitting cabinet
                    // If we want to support splitting cabinet with more large files we need to update this code
                    if (wixFileRow.DiskId >= newMediaRow.DiskId && !wixFileRow.File.Equals(fileToken, StringComparison.InvariantCultureIgnoreCase))
                    {
                        wixFileRow.DiskId++; // Increment DiskID
                    }
                }

                // Update the Last Cabinet Added in the Split Sequence in Dictionary for future callback
                this.lastCabinetAddedToMediaTable[firstCabinetName] = newCabinetName;

                mediaTable.ValidateRows(); // Valdiates DiskDIs, throws Exception as Wix Error if validation fails
            }
            finally
            {
                // Releasing the Mutex here
                mutex.ReleaseMutex();
            }
        }
示例#5
0
        /// <summary>
        /// Creates a work item to create a cabinet.
        /// </summary>
        /// <param name="output">Output for the current database.</param>
        /// <param name="cabinetDir">Directory to create cabinet in.</param>
        /// <param name="mediaRow">MediaRow containing information about the cabinet.</param>
        /// <param name="fileFacades">Collection of files in this cabinet.</param>
        /// <param name="fileTransfers">Array of files to be transfered.</param>
        /// <returns>created CabinetWorkItem object</returns>
        private CabinetWorkItem CreateCabinetWorkItem(Output output, string cabinetDir, MediaRow mediaRow, CompressionLevel compressionLevel, IEnumerable <FileFacade> fileFacades, List <FileTransfer> fileTransfers)
        {
            CabinetWorkItem cabinetWorkItem  = null;
            string          tempCabinetFileX = Path.Combine(this.TempFilesLocation, mediaRow.Cabinet);

            // check for an empty cabinet
            if (!fileFacades.Any())
            {
                string cabinetName = mediaRow.Cabinet;

                // remove the leading '#' from the embedded cabinet name to make the warning easier to understand
                if (cabinetName.StartsWith("#", StringComparison.Ordinal))
                {
                    cabinetName = cabinetName.Substring(1);
                }

                // If building a patch, remind them to run -p for torch.
                if (OutputType.Patch == output.Type)
                {
                    Messaging.Instance.OnMessage(WixWarnings.EmptyCabinet(mediaRow.SourceLineNumbers, cabinetName, true));
                }
                else
                {
                    Messaging.Instance.OnMessage(WixWarnings.EmptyCabinet(mediaRow.SourceLineNumbers, cabinetName));
                }
            }

            ResolvedCabinet resolvedCabinet = this.ResolveCabinet(tempCabinetFileX, fileFacades);

            // create a cabinet work item if it's not being skipped
            if (CabinetBuildOption.BuildAndCopy == resolvedCabinet.BuildOption || CabinetBuildOption.BuildAndMove == resolvedCabinet.BuildOption)
            {
                int maxThreshold = 0; // default to the threshold for best smartcabbing (makes smallest cabinet).

                cabinetWorkItem = new CabinetWorkItem(fileFacades, resolvedCabinet.Path, maxThreshold, compressionLevel /*, this.FileManager*/);
            }
            else // reuse the cabinet from the cabinet cache.
            {
                Messaging.Instance.OnMessage(WixVerboses.ReusingCabCache(mediaRow.SourceLineNumbers, mediaRow.Cabinet, resolvedCabinet.Path));

                try
                {
                    // Ensure the cached cabinet timestamp is current to prevent perpetual incremental builds. The
                    // problematic scenario goes like this. Imagine two cabinets in the cache. Update a file that
                    // goes into one of the cabinets. One cabinet will get rebuilt, the other will be copied from
                    // the cache. Now the file (an input) has a newer timestamp than the reused cabient (an output)
                    // causing the project to look like it perpetually needs a rebuild until all of the reused
                    // cabinets get newer timestamps.
                    File.SetLastWriteTime(resolvedCabinet.Path, DateTime.Now);
                }
                catch (Exception e)
                {
                    Messaging.Instance.OnMessage(WixWarnings.CannotUpdateCabCache(mediaRow.SourceLineNumbers, resolvedCabinet.Path, e.Message));
                }
            }

            if (mediaRow.Cabinet.StartsWith("#", StringComparison.Ordinal))
            {
                Table streamsTable = output.EnsureTable(this.TableDefinitions["_Streams"]);

                Row streamRow = streamsTable.CreateRow(mediaRow.SourceLineNumbers);
                streamRow[0] = mediaRow.Cabinet.Substring(1);
                streamRow[1] = resolvedCabinet.Path;
            }
            else
            {
                string       destinationPath = Path.Combine(cabinetDir, mediaRow.Cabinet);
                FileTransfer transfer;
                if (FileTransfer.TryCreate(resolvedCabinet.Path, destinationPath, CabinetBuildOption.BuildAndMove == resolvedCabinet.BuildOption, "Cabinet", mediaRow.SourceLineNumbers, out transfer))
                {
                    transfer.Built = true;
                    fileTransfers.Add(transfer);
                }
            }

            return(cabinetWorkItem);
        }
示例#6
0
文件: Table.cs 项目: fyodorkor/Data
        /// <summary>
        /// Creates a new row in the table.
        /// </summary>
        /// <param name="sourceLineNumbers">Original source lines for this row.</param>
        /// <param name="add">Specifies whether to only create the row or add it to the table automatically.</param>
        /// <returns>Row created in table.</returns>
        public Row CreateRow(SourceLineNumber sourceLineNumbers, bool add = true)
        {
            Row row;

            switch (this.Name)
            {
            case "BBControl":
                row = new BBControlRow(sourceLineNumbers, this);
                break;

            case "WixBundlePackage":
                row = new WixBundlePackageRow(sourceLineNumbers, this);
                break;

            case "WixBundleExePackage":
                row = new WixBundleExePackageRow(sourceLineNumbers, this);
                break;

            case "WixBundleMsiPackage":
                row = new WixBundleMsiPackageRow(sourceLineNumbers, this);
                break;

            case "WixBundleMspPackage":
                row = new WixBundleMspPackageRow(sourceLineNumbers, this);
                break;

            case "WixBundleMsuPackage":
                row = new WixBundleMsuPackageRow(sourceLineNumbers, this);
                break;

            case "Component":
                row = new ComponentRow(sourceLineNumbers, this);
                break;

            case "WixBundleContainer":
                row = new WixBundleContainerRow(sourceLineNumbers, this);
                break;

            case "Control":
                row = new ControlRow(sourceLineNumbers, this);
                break;

            case "File":
                row = new FileRow(sourceLineNumbers, this);
                break;

            case "WixBundleMsiFeature":
                row = new WixBundleMsiFeatureRow(sourceLineNumbers, this);
                break;

            case "WixBundleMsiProperty":
                row = new WixBundleMsiPropertyRow(sourceLineNumbers, this);
                break;

            case "Media":
                row = new MediaRow(sourceLineNumbers, this);
                break;

            case "WixBundlePayload":
                row = new WixBundlePayloadRow(sourceLineNumbers, this);
                break;

            case "Property":
                row = new PropertyRow(sourceLineNumbers, this);
                break;

            case "WixRelatedBundle":
                row = new WixRelatedBundleRow(sourceLineNumbers, this);
                break;

            case "WixBundleRelatedPackage":
                row = new WixBundleRelatedPackageRow(sourceLineNumbers, this);
                break;

            case "WixBundleRollbackBoundary":
                row = new WixBundleRollbackBoundaryRow(sourceLineNumbers, this);
                break;

            case "Upgrade":
                row = new UpgradeRow(sourceLineNumbers, this);
                break;

            case "WixBundleVariable":
                row = new WixBundleVariableRow(sourceLineNumbers, this);
                break;

            case "WixAction":
                row = new WixActionRow(sourceLineNumbers, this);
                break;

            case "WixApprovedExeForElevation":
                row = new WixApprovedExeForElevationRow(sourceLineNumbers, this);
                break;

            case "WixBundle":
                row = new WixBundleRow(sourceLineNumbers, this);
                break;

            case "WixBundlePackageExitCode":
                row = new WixBundlePackageExitCodeRow(sourceLineNumbers, this);
                break;

            case "WixBundlePatchTargetCode":
                row = new WixBundlePatchTargetCodeRow(sourceLineNumbers, this);
                break;

            case "WixBundleSlipstreamMsp":
                row = new WixBundleSlipstreamMspRow(sourceLineNumbers, this);
                break;

            case "WixBundleUpdate":
                row = new WixBundleUpdateRow(sourceLineNumbers, this);
                break;

            case "WixBundleCatalog":
                row = new WixBundleCatalogRow(sourceLineNumbers, this);
                break;

            case "WixChain":
                row = new WixChainRow(sourceLineNumbers, this);
                break;

            case "WixChainItem":
                row = new WixChainItemRow(sourceLineNumbers, this);
                break;

            case "WixBundlePackageCommandLine":
                row = new WixBundlePackageCommandLineRow(sourceLineNumbers, this);
                break;

            case "WixComplexReference":
                row = new WixComplexReferenceRow(sourceLineNumbers, this);
                break;

            case "WixDeltaPatchFile":
                row = new WixDeltaPatchFileRow(sourceLineNumbers, this);
                break;

            case "WixDeltaPatchSymbolPaths":
                row = new WixDeltaPatchSymbolPathsRow(sourceLineNumbers, this);
                break;

            case "WixFile":
                row = new WixFileRow(sourceLineNumbers, this);
                break;

            case "WixGroup":
                row = new WixGroupRow(sourceLineNumbers, this);
                break;

            case "WixMedia":
                row = new WixMediaRow(sourceLineNumbers, this);
                break;

            case "WixMediaTemplate":
                row = new WixMediaTemplateRow(sourceLineNumbers, this);
                break;

            case "WixMerge":
                row = new WixMergeRow(sourceLineNumbers, this);
                break;

            case "WixPayloadProperties":
                row = new WixPayloadPropertiesRow(sourceLineNumbers, this);
                break;

            case "WixProperty":
                row = new WixPropertyRow(sourceLineNumbers, this);
                break;

            case "WixSimpleReference":
                row = new WixSimpleReferenceRow(sourceLineNumbers, this);
                break;

            case "WixUpdateRegistration":
                row = new WixUpdateRegistrationRow(sourceLineNumbers, this);
                break;

            case "WixVariable":
                row = new WixVariableRow(sourceLineNumbers, this);
                break;

            default:
                row = new Row(sourceLineNumbers, this);
                break;
            }

            if (add)
            {
                this.Rows.Add(row);
            }

            return(row);
        }
示例#7
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));
                        }
                    }
                }
            }
        }
示例#8
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);
            }
        }
示例#9
0
        public void Execute()
        {
            Debug.Assert(OutputType.Patch != this.Output.Type);

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

#if REVISIT_FOR_PATCHING // TODO: Fix this patching related code to work correctly with FileFacades.
            bool copyToPatch   = (allFileRows != null);
            bool copyFromPatch = !copyToPatch;

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

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

            Table patchActualFileTable = this.Output.EnsureTable(this.TableDefinitions["File"]);
            Table 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;
                    RowDictionary <WixFileRow> mediaFileRows;
                    if (!patchMediaFileRows.TryGetValue(diskId, out mediaFileRows))
                    {
                        mediaFileRows = new RowDictionary <WixFileRow>();
                        patchMediaFileRows.Add(diskId, mediaFileRows);
                    }

                    mediaFileRows.Add(patchFileRow);
                }

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

            // index paired transforms
            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 (SubStorage substorage in this.Output.SubStorages)
                {
                    if (substorage.Name.StartsWith("#"))
                    {
                        // no changes necessary for paired transforms
                        continue;
                    }

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

                    this.FileManagerCore.ActiveSubStorage = substorage;

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

                    Table  mainFileTable   = mainTransform.Tables["File"];
                    Output pairedTransform = (Output)pairedTransforms[substorage.Name];

                    // copy Media.LastSequence and index the MsiFileHash table if it exists.
                    if (copyFromPatch)
                    {
                        Table pairedMediaTable = pairedTransform.Tables["Media"];
                        foreach (MediaRow pairedMediaRow in pairedMediaTable.Rows)
                        {
                            MediaRow 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
                    Table pairedFileTable = pairedTransform.Tables["File"];
                    RowDictionary <FileRow> 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;
                            }

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

                            if (copyToPatch) // when copying to the patch, we need compare the underlying files and include all file changes.
                            {
                                ObjectField objectField   = (ObjectField)mainWixFileRow.Fields[6];
                                FileRow     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        |= MsiInterop.MsidbFileAttributesPatchAdded;
                                                pairedFileRow.Attributes        &= ~MsiInterop.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 (Field field in mainFileRow.Fields)
                                            {
                                                field.Modified = false;
                                            }

                                            if (null != pairedFileRow)
                                            {
                                                pairedFileRow.Attributes        &= ~MsiInterop.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        |= MsiInterop.MsidbFileAttributesPatchAdded;
                                    pairedFileRow.Attributes        &= ~MsiInterop.MsidbFileAttributesNoncompressed;
                                    pairedFileRow.Fields[6].Modified = true;
                                    pairedFileRow.Operation          = RowOperation.Add;
                                }
                            }

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

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

                            string     fileId       = mainFileRow.File;
                            WixFileRow patchFileRow = mediaFileRows.Get(fileId);
                            if (copyToPatch)
                            {
                                if (null == patchFileRow)
                                {
                                    FileRow 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))
                                    {
                                        Messaging.Instance.OnMessage(WixErrors.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)
                                {
                                    FileRow pairedFileRow = (FileRow)pairedFileRows.Get(fileId);
                                    for (int i = 0; i < patchFileRow.Fields.Length; i++)
                                    {
                                        string patchValue = patchFileRow[i] == null ? "" : patchFileRow[i].ToString();
                                        string mainValue  = mainFileRow[i] == null ? "" : mainFileRow[i].ToString();

                                        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
                                    Row patchHashRow;
                                    if (!mainMsiFileHashIndex.TryGetValue(patchFileRow.File, out patchHashRow))
                                    {
                                        patchHashRow = patchFileRow.Hash;
                                    }

                                    if (null != patchHashRow)
                                    {
                                        Table mainHashTable = mainTransform.EnsureTable(this.TableDefinitions["MsiFileHash"]);
                                        Row   mainHashRow   = mainHashTable.CreateRow(mainFileRow.SourceLineNumbers);
                                        for (int 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)
                                    {
                                        Table mainAssemblyNameTable = mainTransform.EnsureTable(this.TableDefinitions["MsiAssemblyName"]);
                                        foreach (Row patchAssemblyNameRow in patchAssemblyNameRows)
                                        {
                                            // Copy if there isn't an identical modified/added row already in the transform.
                                            bool foundMatchingModifiedRow = false;
                                            foreach (Row mainAssemblyNameRow in mainAssemblyNameTable.Rows)
                                            {
                                                if (RowOperation.None != mainAssemblyNameRow.Operation && mainAssemblyNameRow.GetPrimaryKey('/').Equals(patchAssemblyNameRow.GetPrimaryKey('/')))
                                                {
                                                    foundMatchingModifiedRow = true;
                                                    break;
                                                }
                                            }

                                            if (!foundMatchingModifiedRow)
                                            {
                                                Row mainAssemblyNameRow = mainAssemblyNameTable.CreateRow(mainFileRow.SourceLineNumbers);
                                                for (int 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.
                                        AddPatchFilesActionToSequenceTable(SequenceTable.AdminExecuteSequence, mainTransform, pairedTransform, mainFileRow);
                                        AddPatchFilesActionToSequenceTable(SequenceTable.InstallExecuteSequence, mainTransform, pairedTransform, mainFileRow);

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

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

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

                                        string streamName = patchTable.Name + "." + patchRow[0] + "." + patchRow[1];
                                        if (MsiInterop.MsiMaxStreamNameLength < streamName.Length)
                                        {
                                            streamName = "_" + Guid.NewGuid().ToString("D").ToUpperInvariant().Replace('-', '_');
                                            Table patchHeadersTable = pairedTransform.EnsureTable(this.TableDefinitions["MsiPatchHeaders"]);
                                            if (0 == patchHeadersTable.Rows.Count)
                                            {
                                                patchHeadersTable.Operation = TableOperation.Add;
                                            }
                                            Row 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;
            }
#endif
            this.FileFacades = allFileRows;
        }
示例#10
0
        public void Execute()
        {
            List <FileTransfer> fileTransfers = new List <FileTransfer>();

            Hashtable directories = new Hashtable();

            RowDictionary <WixMediaRow> wixMediaRows = new RowDictionary <WixMediaRow>(this.WixMediaTable);

            using (Database db = new Database(this.DatabasePath, OpenDatabase.ReadOnly))
            {
                using (View directoryView = db.OpenExecuteView("SELECT `Directory`, `Directory_Parent`, `DefaultDir` FROM `Directory`"))
                {
                    while (true)
                    {
                        using (Record directoryRecord = directoryView.Fetch())
                        {
                            if (null == directoryRecord)
                            {
                                break;
                            }

                            string sourceName = Installer.GetName(directoryRecord.GetString(3), true, this.LongNamesInImage);

                            directories.Add(directoryRecord.GetString(1), new ResolvedDirectory(directoryRecord.GetString(2), sourceName));
                        }
                    }
                }

                using (View fileView = db.OpenView("SELECT `Directory_`, `FileName` FROM `Component`, `File` WHERE `Component`.`Component`=`File`.`Component_` AND `File`.`File`=?"))
                {
                    using (Record fileQueryRecord = new Record(1))
                    {
                        // for each file in the array of uncompressed files
                        foreach (FileFacade facade in this.FileFacades)
                        {
                            MediaRow mediaRow = this.MediaRows.Get(facade.WixFile.DiskId);
                            string   relativeFileLayoutPath = null;

                            WixMediaRow wixMediaRow       = null;
                            string      mediaLayoutFolder = null;

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

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

                            // setup up the query record and find the appropriate file in the
                            // previously executed file view
                            fileQueryRecord[1] = facade.File.File;
                            fileView.Execute(fileQueryRecord);

                            using (Record fileRecord = fileView.Fetch())
                            {
                                if (null == fileRecord)
                                {
                                    throw new WixException(WixErrors.FileIdentifierNotFound(facade.File.SourceLineNumbers, facade.File.File));
                                }

                                relativeFileLayoutPath = Binder.GetFileSourcePath(directories, fileRecord[1], fileRecord[2], this.Compressed, this.LongNamesInImage);
                            }

                            // finally put together the base media layout path and the relative file layout path
                            string       fileLayoutPath = Path.Combine(mediaLayoutDirectory, relativeFileLayoutPath);
                            FileTransfer transfer;
                            if (FileTransfer.TryCreate(facade.WixFile.Source, fileLayoutPath, false, "File", facade.File.SourceLineNumbers, out transfer))
                            {
                                fileTransfers.Add(transfer);
                            }
                        }
                    }
                }
            }

            this.FileTransfers = fileTransfers;
        }
示例#11
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;
                }
            }
        }