예제 #1
0
        /// <summary>
        /// Assigns the file rows to media rows based on Media or MediaTemplate authoring. Updates uncompressed files collection.
        /// </summary>
        /// <param name="fileRows">FileRowCollection</param>
        public void AssignFiles(FileRowCollection fileRows)
        {
            bool     autoAssign          = false;
            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));
            }

            autoAssign = mediaTemplateTable != null && OutputType.Module != this.output.Type ? true : false;

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

                this.cabinets.Add(mergeModuleMediaRow, new FileRowCollection());
            }

            if (autoAssign)
            {
                this.AutoAssignFiles(mediaTable, fileRows);
            }
            else
            {
                this.ManuallyAssignFiles(mediaTable, mergeModuleMediaRow, fileRows);
            }
        }
예제 #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(Table mediaTable, int cabIndex)
        {
            MediaRow currentMediaRow = (MediaRow)mediaTable.CreateRow(null);

            currentMediaRow.DiskId = cabIndex;
            mediaRows.Add(currentMediaRow);
            currentMediaRow.Cabinet = String.Format(this.cabinetNameTemplate, cabIndex);
            cabinets.Add(currentMediaRow, new FileRowCollection());
            return(currentMediaRow);
        }
예제 #3
0
        /// <summary>
        /// Create a deleted or modified row.
        /// </summary>
        /// <param name="table">The table containing the row.</param>
        /// <param name="primaryKeys">The primary keys of the row.</param>
        /// <param name="setRequiredFields">Option to set all required fields with placeholder values.</param>
        /// <returns>The new row.</returns>
        private Row CreateRow(Table table, string primaryKeys, bool setRequiredFields)
        {
            Row row = table.CreateRow(null);

            string[] primaryKeyParts     = primaryKeys.Split('\t');
            int      primaryKeyPartIndex = 0;

            for (int i = 0; i < table.Definition.Columns.Count; i++)
            {
                ColumnDefinition columnDefinition = table.Definition.Columns[i];

                if (columnDefinition.IsPrimaryKey)
                {
                    if (ColumnType.Number == columnDefinition.Type && !columnDefinition.IsLocalizable)
                    {
                        row[i] = Convert.ToInt32(primaryKeyParts[primaryKeyPartIndex++], CultureInfo.InvariantCulture);
                    }
                    else
                    {
                        row[i] = primaryKeyParts[primaryKeyPartIndex++];
                    }
                }
                else if (setRequiredFields)
                {
                    if (ColumnType.Number == columnDefinition.Type && !columnDefinition.IsLocalizable)
                    {
                        row[i] = 1;
                    }
                    else if (ColumnType.Object == columnDefinition.Type)
                    {
                        if (null == this.emptyFile)
                        {
                            this.emptyFile = this.tempFiles.AddExtension("empty");
                            using (FileStream fileStream = File.Create(this.emptyFile))
                            {
                            }
                        }

                        row[i] = this.emptyFile;
                    }
                    else
                    {
                        row[i] = "1";
                    }
                }
            }

            return(row);
        }
예제 #4
0
        /// <summary>
        /// Adds the validation rows to the _Validation table.
        /// </summary>
        /// <param name="validationTable">The _Validation table.</param>
        internal void AddValidationRows(Table validationTable)
        {
            foreach (ColumnDefinition columnDef in this.columns)
            {
                Row row = validationTable.CreateRow(null);

                row[0] = this.name;

                row[1] = columnDef.Name;

                if (columnDef.IsNullable)
                {
                    row[2] = "Y";
                }
                else
                {
                    row[2] = "N";
                }

                if (columnDef.IsMinValueSet)
                {
                    row[3] = columnDef.MinValue;
                }

                if (columnDef.IsMaxValueSet)
                {
                    row[4] = columnDef.MaxValue;
                }

                row[5] = columnDef.KeyTable;

                if (columnDef.IsKeyColumnSet)
                {
                    row[6] = columnDef.KeyColumn;
                }

                if (ColumnCategory.Unknown != columnDef.Category)
                {
                    row[7] = columnDef.Category.ToString();
                }

                row[8] = columnDef.Possibilities;

                row[9] = columnDef.Description;
            }
        }
예제 #5
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(Table mediaTable, int cabIndex, string compressionLevel)
        {
            MediaRow currentMediaRow = (MediaRow)mediaTable.CreateRow(null);

            currentMediaRow.DiskId  = cabIndex;
            currentMediaRow.Cabinet = String.Format(this.cabinetNameTemplate, cabIndex);
            this.mediaRows.Add(currentMediaRow);
            this.cabinets.Add(currentMediaRow, new FileRowCollection());

            Table wixMediaTable = this.output.EnsureTable(this.core.TableDefinitions["WixMedia"]);
            Row   row           = wixMediaTable.CreateRow(null);

            row[0] = cabIndex;
            row[1] = compressionLevel;

            return(currentMediaRow);
        }
예제 #6
0
        public static PayloadInfoRow Create(SourceLineNumberCollection sourceLineNumbers, Output output, string id, string name, string sourceFile,
                                            bool contentFile, bool suppressSignatureValidation, string downloadUrl, string container, PackagingType packaging)
        {
            Table          table = output.Tables["PayloadInfo"];
            PayloadInfoRow row   = (PayloadInfoRow)table.CreateRow(sourceLineNumbers);

            row.Id          = id;
            row.Name        = name;
            row.SourceFile  = sourceFile;
            row.ContentFile = contentFile;
            row.SuppressSignatureValidation = suppressSignatureValidation;
            row.DownloadUrl = downloadUrl;
            row.Container   = container;
            row.Packaging   = packaging;

            PayloadInfoRow.ResolvePayloadInfo(row);
            return(row);
        }
        /// <summary>
        /// Creates new WixGroup rows for a list of items.
        /// </summary>
        /// <param name="parentType">The group type for the parent group in the new rows.</param>
        /// <param name="parentId">The identifier of the parent group in the new rows.</param>
        /// <param name="orderedItems">The list of new items.</param>
        private void CreateNewGroupRows(string parentType, string parentId, List <Item> orderedItems)
        {
            // TODO: MSIs don't guarantee that rows stay in the same order, and technically, neither
            // does WiX (although they do, currently). We probably want to "upgrade" this to a new
            // table that includes a sequence number, and then change the code that uses ordered
            // groups to read from that table instead.
            Table wixGroupTable = this.output.Tables["WixGroup"];

            Debug.Assert(null != wixGroupTable);

            foreach (Item item in orderedItems)
            {
                Row row = wixGroupTable.CreateRow(item.Row.SourceLineNumbers);
                row[0] = parentId;
                row[1] = parentType;
                row[2] = item.Id;
                row[3] = item.Type;
            }
        }
예제 #8
0
        private void UpdateTransformSummaryInformationTable(Table summaryInfoTable, TransformFlags validationFlags)
        {
            // calculate the minimum version of MSI required to process the transform
            int targetMin;
            int updatedMin;
            int minimumVersion = 100;

            if (Int32.TryParse(this.transformSummaryInfo.TargetMinimumVersion, out targetMin) && Int32.TryParse(this.transformSummaryInfo.UpdatedMinimumVersion, out updatedMin))
            {
                minimumVersion = Math.Max(targetMin, updatedMin);
            }

            Hashtable summaryRows = new Hashtable(summaryInfoTable.Rows.Count);

            foreach (Row row in summaryInfoTable.Rows)
            {
                summaryRows[row[0]] = row;

                if ((int)SummaryInformation.Transform.CodePage == (int)row[0])
                {
                    row.Fields[1].Data         = this.transformSummaryInfo.UpdatedSummaryInfoCodepage;
                    row.Fields[1].PreviousData = this.transformSummaryInfo.TargetSummaryInfoCodepage;
                }
                else if ((int)SummaryInformation.Transform.TargetPlatformAndLanguage == (int)row[0])
                {
                    row[1] = this.transformSummaryInfo.TargetPlatformAndLanguage;
                }
                else if ((int)SummaryInformation.Transform.UpdatedPlatformAndLanguage == (int)row[0])
                {
                    row[1] = this.transformSummaryInfo.UpdatedPlatformAndLanguage;
                }
                else if ((int)SummaryInformation.Transform.ProductCodes == (int)row[0])
                {
                    row[1] = String.Concat(this.transformSummaryInfo.TargetProductCode, this.transformSummaryInfo.TargetProductVersion, ';', this.transformSummaryInfo.UpdatedProductCode, this.transformSummaryInfo.UpdatedProductVersion, ';', this.transformSummaryInfo.TargetUpgradeCode);
                }
                else if ((int)SummaryInformation.Transform.InstallerRequirement == (int)row[0])
                {
                    row[1] = minimumVersion.ToString(CultureInfo.InvariantCulture);
                }
                else if ((int)SummaryInformation.Transform.Security == (int)row[0])
                {
                    row[1] = "4";
                }
            }

            if (!summaryRows.Contains((int)SummaryInformation.Transform.TargetPlatformAndLanguage))
            {
                Row summaryRow = summaryInfoTable.CreateRow(null);
                summaryRow[0] = (int)SummaryInformation.Transform.TargetPlatformAndLanguage;
                summaryRow[1] = this.transformSummaryInfo.TargetPlatformAndLanguage;
            }

            if (!summaryRows.Contains((int)SummaryInformation.Transform.UpdatedPlatformAndLanguage))
            {
                Row summaryRow = summaryInfoTable.CreateRow(null);
                summaryRow[0] = (int)SummaryInformation.Transform.UpdatedPlatformAndLanguage;
                summaryRow[1] = this.transformSummaryInfo.UpdatedPlatformAndLanguage;
            }

            if (!summaryRows.Contains((int)SummaryInformation.Transform.ValidationFlags))
            {
                Row summaryRow = summaryInfoTable.CreateRow(null);
                summaryRow[0] = (int)SummaryInformation.Transform.ValidationFlags;
                summaryRow[1] = ((int)validationFlags).ToString(CultureInfo.InvariantCulture);
            }

            if (!summaryRows.Contains((int)SummaryInformation.Transform.InstallerRequirement))
            {
                Row summaryRow = summaryInfoTable.CreateRow(null);
                summaryRow[0] = (int)SummaryInformation.Transform.InstallerRequirement;
                summaryRow[1] = minimumVersion.ToString(CultureInfo.InvariantCulture);
            }

            if (!summaryRows.Contains((int)SummaryInformation.Transform.Security))
            {
                Row summaryRow = summaryInfoTable.CreateRow(null);
                summaryRow[0] = (int)SummaryInformation.Transform.Security;
                summaryRow[1] = "4";
            }
        }
        /// <summary>
        /// Assigns the file rows to media rows based on Media or MediaTemplate authoring. Updates uncompressed files collection.
        /// </summary>
        /// <param name="fileRows">FileRowCollection</param>
        public void AssignFiles(FileRowCollection fileRows)
        {
            bool autoAssign = false;
            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));
            }

            autoAssign = mediaTemplateTable != null && OutputType.Module != this.output.Type ? true : false;

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

                this.cabinets.Add(mergeModuleMediaRow, new FileRowCollection());
            }

            if (autoAssign)
            {
                this.AutoAssignFiles(mediaTable, fileRows);
            }
            else
            {
                this.ManuallyAssignFiles(mediaTable, mergeModuleMediaRow, fileRows);
            }
        }
예제 #10
0
        /// <summary>
        /// Create the #transform for the given main transform.
        /// </summary>
        /// <param name="patchId">patch GUID from patch authoring.</param>
        /// <param name="mainTransform">transform generated by torch.</param>
        /// <param name="mediaRow">media authored into patch.</param>
        /// <param name="productCode">output string to receive ProductCode.</param>
        public Output BuildPairedTransform(string patchId, Output mainTransform, MediaRow mediaRow, ref string productCode)
        {
            Output pairedTransform = new Output(null);

            pairedTransform.Type     = OutputType.Transform;
            pairedTransform.Codepage = mainTransform.Codepage;

            // lookup productVersion property to correct summaryInformation
            string newProductVersion = null;
            Table  mainPropertyTable = mainTransform.Tables["Property"];

            if (mainPropertyTable != null)
            {
                foreach (Row row in mainPropertyTable.Rows)
                {
                    if ("ProductVersion" == (string)row[0])
                    {
                        newProductVersion = (string)row[1];
                    }
                }
            }

            // TODO: build class for manipulating SummaryInformation table
            Table mainSummaryTable = mainTransform.Tables["_SummaryInformation"];
            // add required properties
            Hashtable mainSummaryRows = new Hashtable();

            foreach (Row mainSummaryRow in mainSummaryTable.Rows)
            {
                mainSummaryRows[mainSummaryRow[0]] = mainSummaryRow;
            }
            if (!mainSummaryRows.Contains((int)SummaryInformation.Transform.ValidationFlags))
            {
                Row mainSummaryRow = mainSummaryTable.CreateRow(null);
                mainSummaryRow[0] = (int)SummaryInformation.Transform.ValidationFlags;
                mainSummaryRow[1] = "0";
            }

            // copy summary information from core transform
            Table pairedSummaryTable = pairedTransform.EnsureTable(this.tableDefinitions["_SummaryInformation"]);

            foreach (Row mainSummaryRow in mainSummaryTable.Rows)
            {
                string value = (string)mainSummaryRow[1];
                switch ((SummaryInformation.Transform)mainSummaryRow[0])
                {
                case SummaryInformation.Transform.ProductCodes:
                    string[] propertyData      = value.Split(';');
                    string   oldProductVersion = propertyData[0].Substring(38);
                    string   upgradeCode       = propertyData[2];
                    productCode = propertyData[0].Substring(0, 38);
                    if (newProductVersion == null)
                    {
                        newProductVersion = oldProductVersion;
                    }

                    // force mainTranform to old;new;upgrade and pairedTransform to new;new;upgrade
                    mainSummaryRow[1] = String.Concat(productCode, oldProductVersion, ';', productCode, newProductVersion, ';', upgradeCode);
                    value             = String.Concat(productCode, newProductVersion, ';', productCode, newProductVersion, ';', upgradeCode);
                    break;

                case SummaryInformation.Transform.ValidationFlags:
                    // TODO: ensure this row exists in mainSummaryTable!!!!
                    // TODO: author these settings in patch XML or set in torch.exe
                    int i = Convert.ToInt32(value);
                    i |= (int)SummaryInformation.TransformFlags.ErrorAddExistingRow;
                    i |= (int)SummaryInformation.TransformFlags.ErrorDeleteMissingRow;
                    i |= (int)SummaryInformation.TransformFlags.ErrorAddExistingTable;
                    i |= (int)SummaryInformation.TransformFlags.ErrorDeleteMissingTable;
                    i |= (int)SummaryInformation.TransformFlags.ErrorUpdateMissingRow;
                    i |= (int)SummaryInformation.TransformFlags.ValidateProduct;
                    mainSummaryRow[1] = value = i.ToString();
                    break;
                }
                Row pairedSummaryRow = pairedSummaryTable.CreateRow(null);
                pairedSummaryRow[0] = mainSummaryRow[0];
                pairedSummaryRow[1] = value;
            }

            if (productCode == null)
            {
                throw new InvalidOperationException("Could not determine ProductCode from transform summary information");
            }

            // copy File table
            Table mainFileTable    = mainTransform.Tables["File"];
            Table mainWixFileTable = mainTransform.Tables["WixFile"];

            if (mainFileTable != null)
            {
                FileRowCollection mainFileRows = new FileRowCollection();
                mainFileRows.AddRange(mainFileTable.Rows);

                Table pairedFileTable = pairedTransform.EnsureTable(mainFileTable.Definition);
                foreach (Row mainWixFileRow in mainWixFileTable.Rows)
                {
                    FileRow mainFileRow = mainFileRows[(string)mainWixFileRow[0]];

                    // set File.Sequence to non null to satisfy transform bind
                    mainFileRow.Sequence = 1;

                    // delete's don't need rows in the paired transform
                    if (mainFileRow.Operation == RowOperation.Delete)
                    {
                        continue;
                    }

                    FileRow pairedFileRow = (FileRow)pairedFileTable.CreateRow(null);
                    pairedFileRow.Operation = RowOperation.Modify;
                    for (int i = 0; i < mainFileRow.Fields.Length; i++)
                    {
                        object value = mainFileRow[i];
                        pairedFileRow[i] = value;
                    }

                    // override authored media for patch bind
                    // TODO: consider using File/@DiskId for patch media
                    mainFileRow.DiskId = mediaRow.DiskId;
                    mainWixFileRow[5]  = mediaRow.DiskId;
                    // suppress any change to File.Sequence to avoid bloat
                    mainFileRow.Fields[7].Modified = false;

                    // force File row to appear in the transform
                    if (RowOperation.Modify == mainFileRow.Operation)
                    {
                        mainFileRow.Operation            = RowOperation.Modify;
                        pairedFileRow.Attributes        |= MsiInterop.MsidbFileAttributesPatchAdded;
                        pairedFileRow.Fields[6].Modified = true;
                        pairedFileRow.Operation          = RowOperation.Modify;
                    }
                    else if (RowOperation.Add == mainFileRow.Operation)
                    {
                        // set msidbFileAttributesPatchAdded
                        pairedFileRow.Attributes        |= MsiInterop.MsidbFileAttributesPatchAdded;
                        pairedFileRow.Fields[6].Modified = true;
                        pairedFileRow.Operation          = RowOperation.Add;
                    }
                    else
                    {
                        pairedFileRow.Attributes         = mainFileRow.Attributes;
                        pairedFileRow.Fields[6].Modified = false;
                    }
                }
            }

            // add Media row to pairedTransform
            Table pairedMediaTable = pairedTransform.EnsureTable(this.tableDefinitions["Media"]);
            Row   pairedMediaRow   = pairedMediaTable.CreateRow(null);

            pairedMediaRow.Operation = RowOperation.Add;
            for (int i = 0; i < mediaRow.Fields.Length; i++)
            {
                pairedMediaRow[i] = mediaRow[i];
            }

            // add PatchPackage for this Media
            Table pairedPackageTable = pairedTransform.EnsureTable(this.tableDefinitions["PatchPackage"]);

            pairedPackageTable.Operation = TableOperation.Add;
            Row pairedPackageRow = pairedPackageTable.CreateRow(null);

            pairedPackageRow.Operation = RowOperation.Add;
            pairedPackageRow[0]        = patchId;
            pairedPackageRow[1]        = mediaRow.DiskId;

            // add property to both identify client patches and whether those patches are removable or not
            string patchPropertyId       = new Guid(patchId).ToString("N", CultureInfo.InvariantCulture).ToUpper();
            int    allowRemoval          = 0;
            Table  msiPatchMetadataTable = this.patch.Tables["MsiPatchMetadata"];

            if (null != msiPatchMetadataTable)
            {
                foreach (Row msiPatchMetadataRow in msiPatchMetadataTable.Rows)
                {
                    if (string.Empty == (string)msiPatchMetadataRow[0] && "AllowRemoval" == (string)msiPatchMetadataRow[1])
                    {
                        allowRemoval = Convert.ToInt32((string)msiPatchMetadataRow[2]);
                    }
                }
            }
            Table pairedPropertyTable = pairedTransform.EnsureTable(this.tableDefinitions["Property"]);

            pairedPropertyTable.Operation = TableOperation.Add;
            Row pairedPropertyRow = pairedPropertyTable.CreateRow(null);

            pairedPropertyRow.Operation = RowOperation.Add;
            pairedPropertyRow[0]        = string.Format(CultureInfo.InvariantCulture, "_{0}.AllowRemoval", patchPropertyId);
            pairedPropertyRow[1]        = allowRemoval.ToString();

            return(pairedTransform);
        }
예제 #11
0
        /// <summary>
        /// Finalize the sequence tables.
        /// </summary>
        /// <param name="tables">The collection of all tables.</param>
        /// <remarks>
        /// Creates the sequence elements.  Occurs during finalization because its
        /// not known if sequences refer to custom actions or dialogs during decompilation.
        /// </remarks>
        private void FinalizeSequenceTables(TableCollection tables)
        {
            // finalize the normal sequence tables
            if (OutputType.Product == this.outputType && !this.treatProductAsModule)
            {
                foreach (SequenceTable sequenceTable in Enum.GetValues(typeof(SequenceTable)))
                {
                    // if suppressing UI elements, skip UI-related sequence tables
                    if (this.suppressUI && ("AdminUISequence" == sequenceTable.ToString() || "InstallUISequence" == sequenceTable.ToString()))
                    {
                        continue;
                    }

                    Table actionsTable = new Table(null, this.tableDefinitions["WixAction"]);
                    Table table = tables[sequenceTable.ToString()];

                    if (null != table)
                    {
                        ArrayList actionRows = new ArrayList();
                        bool needAbsoluteScheduling = this.suppressRelativeActionSequencing;
                        WixActionRowCollection nonSequencedActionRows = new WixActionRowCollection();
                        WixActionRowCollection suppressedRelativeActionRows = new WixActionRowCollection();

                        // create a sorted array of actions in this table
                        foreach (Row row in table.Rows)
                        {
                            WixActionRow actionRow = (WixActionRow)actionsTable.CreateRow(null);

                            actionRow.Action = Convert.ToString(row[0]);

                            if (null != row[1])
                            {
                                actionRow.Condition = Convert.ToString(row[1]);
                            }

                            actionRow.Sequence = Convert.ToInt32(row[2]);

                            actionRow.SequenceTable = sequenceTable;

                            actionRows.Add(actionRow);
                        }
                        actionRows.Sort();

                        for (int i = 0; i < actionRows.Count && !needAbsoluteScheduling; i++)
                        {
                            WixActionRow actionRow = (WixActionRow)actionRows[i];
                            WixActionRow standardActionRow = this.standardActions[actionRow.SequenceTable, actionRow.Action];

                            // create actions for custom actions, dialogs, AppSearch when its moved, and standard actions with non-standard conditions
                            if ("AppSearch" == actionRow.Action || null == standardActionRow || actionRow.Condition != standardActionRow.Condition)
                            {
                                WixActionRow previousActionRow = null;
                                WixActionRow nextActionRow = null;

                                // find the previous action row if there is one
                                if (0 <= i - 1)
                                {
                                    previousActionRow = (WixActionRow)actionRows[i - 1];
                                }

                                // find the next action row if there is one
                                if (actionRows.Count > i + 1)
                                {
                                    nextActionRow = (WixActionRow)actionRows[i + 1];
                                }

                                // the logic for setting the before or after attribute for an action:
                                // 1. If more than one action shares the same sequence number, everything must be absolutely sequenced.
                                // 2. If the next action is a standard action and is 1 sequence number higher, this action occurs before it.
                                // 3. If the previous action is a standard action and is 1 sequence number lower, this action occurs after it.
                                // 4. If this action is not standard and the previous action is 1 sequence number lower and does not occur before this action, this action occurs after it.
                                // 5. If this action is not standard and the previous action does not have the same sequence number and the next action is 1 sequence number higher, this action occurs before it.
                                // 6. If this action is AppSearch and has all standard information, ignore it.
                                // 7. If this action is standard and has a non-standard condition, create the action without any scheduling information.
                                // 8. Everything must be absolutely sequenced.
                                if ((null != previousActionRow && actionRow.Sequence == previousActionRow.Sequence) || (null != nextActionRow && actionRow.Sequence == nextActionRow.Sequence))
                                {
                                    needAbsoluteScheduling = true;
                                }
                                else if (null != nextActionRow && null != this.standardActions[sequenceTable, nextActionRow.Action] && actionRow.Sequence + 1 == nextActionRow.Sequence)
                                {
                                    actionRow.Before = nextActionRow.Action;
                                }
                                else if (null != previousActionRow && null != this.standardActions[sequenceTable, previousActionRow.Action] && actionRow.Sequence - 1 == previousActionRow.Sequence)
                                {
                                    actionRow.After = previousActionRow.Action;
                                }
                                else if (null == standardActionRow && null != previousActionRow && actionRow.Sequence - 1 == previousActionRow.Sequence && previousActionRow.Before != actionRow.Action)
                                {
                                    actionRow.After = previousActionRow.Action;
                                }
                                else if (null == standardActionRow && null != previousActionRow && actionRow.Sequence != previousActionRow.Sequence && null != nextActionRow && actionRow.Sequence + 1 == nextActionRow.Sequence)
                                {
                                    actionRow.Before = nextActionRow.Action;
                                }
                                else if ("AppSearch" == actionRow.Action && null != standardActionRow && actionRow.Sequence == standardActionRow.Sequence && actionRow.Condition == standardActionRow.Condition)
                                {
                                    // ignore an AppSearch row which has the WiX standard sequence and a standard condition
                                }
                                else if (null != standardActionRow && actionRow.Condition != standardActionRow.Condition) // standard actions get their standard sequence numbers
                                {
                                    nonSequencedActionRows.Add(actionRow);
                                }
                                else if (0 < actionRow.Sequence)
                                {
                                    needAbsoluteScheduling = true;
                                }
                            }
                            else
                            {
                                suppressedRelativeActionRows.Add(actionRow);
                            }
                        }

                        // create the actions now that we know if they must be absolutely or relatively scheduled
                        foreach (WixActionRow actionRow in actionRows)
                        {
                            if (needAbsoluteScheduling)
                            {
                                // remove any before/after information to ensure this is absolutely sequenced
                                actionRow.Before = null;
                                actionRow.After = null;
                            }
                            else if (nonSequencedActionRows.Contains(actionRow.SequenceTable, actionRow.Action))
                            {
                                // clear the sequence attribute to ensure this action is scheduled without a sequence number (or before/after)
                                actionRow.Sequence = 0;
                            }
                            else if (suppressedRelativeActionRows.Contains(actionRow.SequenceTable, actionRow.Action))
                            {
                                // skip the suppressed relatively scheduled action rows
                                continue;
                            }

                            // create the action element
                            this.CreateActionElement(actionRow);
                        }
                    }
                }
            }
            else if (OutputType.Module == this.outputType || this.treatProductAsModule) // finalize the Module sequence tables
            {
                foreach (SequenceTable sequenceTable in Enum.GetValues(typeof(SequenceTable)))
                {
                    // if suppressing UI elements, skip UI-related sequence tables
                    if (this.suppressUI && ("AdminUISequence" == sequenceTable.ToString() || "InstallUISequence" == sequenceTable.ToString()))
                    {
                        continue;
                    }

                    Table actionsTable = new Table(null, this.tableDefinitions["WixAction"]);
                    Table table = tables[String.Concat("Module", sequenceTable.ToString())];

                    if (null != table)
                    {
                        foreach (Row row in table.Rows)
                        {
                            WixActionRow actionRow = (WixActionRow)actionsTable.CreateRow(null);

                            actionRow.Action = Convert.ToString(row[0]);

                            if (null != row[1])
                            {
                                actionRow.Sequence = Convert.ToInt32(row[1]);
                            }

                            if (null != row[2] && null != row[3])
                            {
                                switch (Convert.ToInt32(row[3]))
                                {
                                    case 0:
                                        actionRow.Before = Convert.ToString(row[2]);
                                        break;
                                    case 1:
                                        actionRow.After = Convert.ToString(row[2]);
                                        break;
                                    default:
                                        this.core.OnMessage(WixWarnings.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[3].Column.Name, row[3]));
                                        break;
                                }
                            }

                            if (null != row[4])
                            {
                                actionRow.Condition = Convert.ToString(row[4]);
                            }

                            actionRow.SequenceTable = sequenceTable;

                            // create action elements for non-standard actions
                            if (null == this.standardActions[actionRow.SequenceTable, actionRow.Action] || null != actionRow.After || null != actionRow.Before)
                            {
                                this.CreateActionElement(actionRow);
                            }
                        }
                    }
                }
            }
        }
예제 #12
0
        /// <summary>
        /// Assign files to cabinets based on MediaTemplate authoring.
        /// </summary>
        /// <param name="fileRows">FileRowCollection</param>
        private void AutoAssignFiles(Table mediaTable, FileRowCollection fileRows)
        {
            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 (FileRow fileRow in fileRows)
            {
                // 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 == output.Type &&
                    (YesNoType.No == fileRow.Compressed ||
                     (YesNoType.NotSet == fileRow.Compressed && !this.filesCompressed)))
                {
                    uncompressedFileRows.Add(fileRow);
                    continue;
                }

                FileInfo fileInfo = null;

                // Get the file size
                try
                {
                    fileInfo = new FileInfo(fileRow.Source);
                }
                catch (ArgumentException)
                {
                    this.core.OnMessage(WixErrors.InvalidFileName(fileRow.SourceLineNumbers, fileRow.Source));
                }
                catch (PathTooLongException)
                {
                    this.core.OnMessage(WixErrors.InvalidFileName(fileRow.SourceLineNumbers, fileRow.Source));
                }
                catch (NotSupportedException)
                {
                    this.core.OnMessage(WixErrors.InvalidFileName(fileRow.SourceLineNumbers, fileRow.Source));
                }

                if (fileInfo.Exists)
                {
                    if (fileInfo.Length > Int32.MaxValue)
                    {
                        throw new WixException(WixErrors.FileTooLarge(fileRow.SourceLineNumbers, fileRow.Source));
                    }

                    fileRow.FileSize = Convert.ToInt32(fileInfo.Length, CultureInfo.InvariantCulture);
                }

                if (currentCabIndex == MaxCabIndex)
                {
                    // Associate current file with last cab (irrespective of the size) and cab index is not incremented anymore.
                    FileRowCollection cabinetFileRow = (FileRowCollection)this.cabinets[currentMediaRow];
                    fileRow.DiskId = currentCabIndex;
                    cabinetFileRow.Add(fileRow);
                    continue;
                }

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

                if (currentPreCabSize > maxPreCabSizeInBytes)
                {
                    // Overflow due to current file
                    currentMediaRow = this.AddMediaRow(mediaTable, ++currentCabIndex, mediaTemplateRow.CompressionLevel);

                    FileRowCollection cabinetFileRow = (FileRowCollection)this.cabinets[currentMediaRow];
                    fileRow.DiskId = currentCabIndex;
                    cabinetFileRow.Add(fileRow);
                    // Now files larger than MaxUncompressedMediaSize will be the only file in its cabinet so as to respect MaxUncompressedMediaSize
                    currentPreCabSize = (ulong)fileRow.FileSize;
                }
                else
                {
                    // File fits in the current cab.
                    if (currentMediaRow == null)
                    {
                        // Create new cab and MediaRow
                        currentMediaRow = this.AddMediaRow(mediaTable, ++currentCabIndex, mediaTemplateRow.CompressionLevel);
                    }

                    // Associate current file with current cab.
                    FileRowCollection cabinetFileRow = (FileRowCollection)this.cabinets[currentMediaRow];
                    fileRow.DiskId = currentCabIndex;
                    cabinetFileRow.Add(fileRow);
                }
            }

            // If there are uncompressed files and no MediaRow, create a default one.
            if (uncompressedFileRows.Count > 0 && mediaTable.Rows.Count == 0)
            {
                MediaRow defaultMediaRow = (MediaRow)mediaTable.CreateRow(null);
                defaultMediaRow.DiskId = 1;
                mediaRows.Add(defaultMediaRow);
            }
        }
예제 #13
0
        /// <summary>
        /// Unbind an MSI transform file.
        /// </summary>
        /// <param name="transformFile">The transform file.</param>
        /// <param name="exportBasePath">The path where files should be exported.</param>
        /// <returns>The unbound transform.</returns>
        private Output UnbindTransform(string transformFile, string exportBasePath)
        {
            Output transform = new Output(SourceLineNumberCollection.FromFileName(transformFile));

            transform.Type = OutputType.Transform;

            // get the summary information table
            using (SummaryInformation summaryInformation = new SummaryInformation(transformFile))
            {
                Table table = transform.Tables.EnsureTable(null, this.tableDefinitions["_SummaryInformation"]);

                for (int i = 1; 19 >= i; i++)
                {
                    string value = summaryInformation.GetProperty(i);

                    if (0 < value.Length)
                    {
                        Row row = table.CreateRow(transform.SourceLineNumbers);
                        row[0] = i;
                        row[1] = value;
                    }
                }
            }

            // create a schema msi which hopefully matches the table schemas in the transform
            Output schemaOutput    = new Output(null);
            string msiDatabaseFile = Path.Combine(this.tempFiles.BasePath, "schema.msi");

            foreach (TableDefinition tableDefinition in this.tableDefinitions)
            {
                // skip unreal tables and the Patch table
                if (!tableDefinition.IsUnreal && "Patch" != tableDefinition.Name)
                {
                    schemaOutput.EnsureTable(tableDefinition);
                }
            }

            // bind the schema msi
            Binder binder = new Binder();

            binder.SuppressAddingValidationRows = true;
            binder.WixVariableResolver          = new WixVariableResolver();
            binder.GenerateDatabase(schemaOutput, msiDatabaseFile);

            // apply the transform to the database and retrieve the modifications
            Hashtable addedRows = new Hashtable();
            Table     transformViewTable;

            using (Database msiDatabase = new Database(msiDatabaseFile, OpenDatabase.Transact))
            {
                // apply the transform with the ViewTransform option to collect all the modifications
                msiDatabase.ApplyTransform(transformFile, TransformErrorConditions.All | TransformErrorConditions.ViewTransform);

                // unbind the database
                Output transformViewOutput = this.UnbindDatabase(msiDatabaseFile, msiDatabase, OutputType.Product, exportBasePath);

                // index the added and possibly modified rows (added rows may also appears as modified rows)
                transformViewTable = transformViewOutput.Tables["_TransformView"];
                Hashtable modifiedRows = new Hashtable();
                foreach (Row row in transformViewTable.Rows)
                {
                    string tableName   = (string)row[0];
                    string columnName  = (string)row[1];
                    string primaryKeys = (string)row[2];

                    if ("INSERT" == columnName)
                    {
                        string index = String.Concat(tableName, ':', primaryKeys);

                        addedRows.Add(index, null);
                    }
                    else if ("CREATE" != columnName && "DELETE" != columnName && "DROP" != columnName && null != primaryKeys) // modified row
                    {
                        string index = String.Concat(tableName, ':', primaryKeys);

                        modifiedRows[index] = row;
                    }
                }

                // create placeholder rows for modified rows to make the transform insert the updated values when its applied
                foreach (Row row in modifiedRows.Values)
                {
                    string tableName   = (string)row[0];
                    string columnName  = (string)row[1];
                    string primaryKeys = (string)row[2];

                    string index = String.Concat(tableName, ':', primaryKeys);

                    // ignore information for added rows
                    if (!addedRows.Contains(index))
                    {
                        Table table = schemaOutput.Tables[tableName];
                        this.CreateRow(table, primaryKeys, true);
                    }
                }
            }

            // re-bind the schema output with the placeholder rows
            binder.GenerateDatabase(schemaOutput, msiDatabaseFile);

            // apply the transform to the database and retrieve the modifications
            using (Database msiDatabase = new Database(msiDatabaseFile, OpenDatabase.Transact))
            {
                // apply the transform
                msiDatabase.ApplyTransform(transformFile, TransformErrorConditions.All);

                // commit the database to guard against weird errors with streams
                msiDatabase.Commit();

                // unbind the database
                Output output = this.UnbindDatabase(msiDatabaseFile, msiDatabase, OutputType.Product, exportBasePath);

                // index all the rows to easily find modified rows
                Hashtable rows = new Hashtable();
                foreach (Table table in output.Tables)
                {
                    foreach (Row row in table.Rows)
                    {
                        rows.Add(String.Concat(table.Name, ':', row.GetPrimaryKey('\t')), row);
                    }
                }

                // process the _TransformView rows into transform rows
                foreach (Row row in transformViewTable.Rows)
                {
                    string tableName   = (string)row[0];
                    string columnName  = (string)row[1];
                    string primaryKeys = (string)row[2];

                    Table table = transform.Tables.EnsureTable(null, this.tableDefinitions[tableName]);

                    if ("CREATE" == columnName) // added table
                    {
                        table.Operation = TableOperation.Add;
                    }
                    else if ("DELETE" == columnName) // deleted row
                    {
                        Row deletedRow = this.CreateRow(table, primaryKeys, false);
                        deletedRow.Operation = RowOperation.Delete;
                    }
                    else if ("DROP" == columnName) // dropped table
                    {
                        table.Operation = TableOperation.Drop;
                    }
                    else if ("INSERT" == columnName) // added row
                    {
                        string index    = String.Concat(tableName, ':', primaryKeys);
                        Row    addedRow = (Row)rows[index];
                        addedRow.Operation = RowOperation.Add;
                        table.Rows.Add(addedRow);
                    }
                    else if (null != primaryKeys) // modified row
                    {
                        string index = String.Concat(tableName, ':', primaryKeys);

                        // the _TransformView table includes information for added rows
                        // that looks like modified rows so it sometimes needs to be ignored
                        if (!addedRows.Contains(index))
                        {
                            Row modifiedRow = (Row)rows[index];

                            // mark the field as modified
                            int indexOfModifiedValue = modifiedRow.TableDefinition.Columns.IndexOf(columnName);
                            modifiedRow.Fields[indexOfModifiedValue].Modified = true;

                            // move the modified row into the transform the first time its encountered
                            if (RowOperation.None == modifiedRow.Operation)
                            {
                                modifiedRow.Operation = RowOperation.Modify;
                                table.Rows.Add(modifiedRow);
                            }
                        }
                    }
                    else // added column
                    {
                        table.Definition.Columns[columnName].Added = true;
                    }
                }
            }

            return(transform);
        }
예제 #14
0
        /// <summary>
        /// Unbind an MSI database file.
        /// </summary>
        /// <param name="databaseFile">The database file.</param>
        /// <param name="database">The opened database.</param>
        /// <param name="outputType">The type of output to create.</param>
        /// <param name="exportBasePath">The path where files should be exported.</param>
        /// <returns>The output representing the database.</returns>
        private Output UnbindDatabase(string databaseFile, Database database, OutputType outputType, string exportBasePath)
        {
            string modularizationGuid = null;
            Output output             = new Output(SourceLineNumberCollection.FromFileName(databaseFile));
            View   validationView     = null;

            // set the output type
            output.Type = outputType;

            // get the codepage
            database.Export("_ForceCodepage", this.TempFilesLocation, "_ForceCodepage.idt");
            using (StreamReader sr = File.OpenText(Path.Combine(this.TempFilesLocation, "_ForceCodepage.idt")))
            {
                string line;

                while (null != (line = sr.ReadLine()))
                {
                    string[] data = line.Split('\t');

                    if (2 == data.Length)
                    {
                        output.Codepage = Convert.ToInt32(data[0], CultureInfo.InvariantCulture);
                    }
                }
            }

            // get the summary information table
            using (SummaryInformation summaryInformation = new SummaryInformation(database))
            {
                Table table = new Table(null, this.tableDefinitions["_SummaryInformation"]);

                for (int i = 1; 19 >= i; i++)
                {
                    string value = summaryInformation.GetProperty(i);

                    if (0 < value.Length)
                    {
                        Row row = table.CreateRow(output.SourceLineNumbers);
                        row[0] = i;
                        row[1] = value;
                    }
                }

                output.Tables.Add(table);
            }

            try
            {
                // open a view on the validation table if it exists
                if (database.TableExists("_Validation"))
                {
                    validationView = database.OpenView("SELECT * FROM `_Validation` WHERE `Table` = ? AND `Column` = ?");
                }

                // get the normal tables
                using (View tablesView = database.OpenExecuteView("SELECT * FROM _Tables"))
                {
                    Record tableRecord;

                    while (null != (tableRecord = tablesView.Fetch()))
                    {
                        string tableName = tableRecord.GetString(1);

                        using (View tableView = database.OpenExecuteView(String.Format(CultureInfo.InvariantCulture, "SELECT * FROM `{0}`", tableName)))
                        {
                            Record          rowRecord;
                            Table           table;
                            TableDefinition tableDefinition;

                            if (this.tableDefinitions.Contains(tableName))
                            {
                                tableDefinition = this.tableDefinitions[tableName];

                                // TODO: verify table definitions
                                // - error for different column name or data type
                                // - warn for additional columns
                                // - need extra info for new columns in standard tables (MSI 4.0 changes)
                            }
                            else // custom table
                            {
                                TableDefinition customTableDefinition  = new TableDefinition(tableName, false, false);
                                Hashtable       customTablePrimaryKeys = new Hashtable();

                                Record customColumnNameRecord = tableView.GetColumnInfo(MsiInterop.MSICOLINFONAMES);
                                Record customColumnTypeRecord = tableView.GetColumnInfo(MsiInterop.MSICOLINFOTYPES);
                                int    customColumnCount      = customColumnNameRecord.GetFieldCount();

                                // index the primary keys
                                using (Record primaryKeysRecord = database.PrimaryKeys(tableName))
                                {
                                    int primaryKeysFieldCount = primaryKeysRecord.GetFieldCount();

                                    for (int i = 1; i <= primaryKeysFieldCount; i++)
                                    {
                                        customTablePrimaryKeys[primaryKeysRecord.GetString(i)] = null;
                                    }
                                }

                                for (int i = 1; i <= customColumnCount; i++)
                                {
                                    string columnName = customColumnNameRecord.GetString(i);
                                    string idtType    = customColumnTypeRecord.GetString(i);

                                    ColumnType columnType;
                                    int        length;
                                    bool       nullable;

                                    ColumnCategory       columnCategory       = ColumnCategory.Unknown;
                                    ColumnModularizeType columnModularizeType = ColumnModularizeType.None;
                                    bool   primary      = customTablePrimaryKeys.Contains(columnName);
                                    bool   minValueSet  = false;
                                    int    minValue     = -1;
                                    bool   maxValueSet  = false;
                                    int    maxValue     = -1;
                                    string keyTable     = null;
                                    bool   keyColumnSet = false;
                                    int    keyColumn    = -1;
                                    string category     = null;
                                    string set          = null;
                                    string description  = null;

                                    // get the column type, length, and whether its nullable
                                    switch (Char.ToLower(idtType[0], CultureInfo.InvariantCulture))
                                    {
                                    case 'i':
                                        columnType = ColumnType.Number;
                                        break;

                                    case 'l':
                                        columnType = ColumnType.Localized;
                                        break;

                                    case 's':
                                        columnType = ColumnType.String;
                                        break;

                                    case 'v':
                                        columnType = ColumnType.Object;
                                        break;

                                    default:
                                        // TODO: error
                                        columnType = ColumnType.Unknown;
                                        break;
                                    }
                                    length   = Convert.ToInt32(idtType.Substring(1), CultureInfo.InvariantCulture);
                                    nullable = Char.IsUpper(idtType[0]);

                                    // try to get validation information
                                    if (null != validationView)
                                    {
                                        Record validationRecord = new Record(2);
                                        validationRecord.SetString(1, tableName);
                                        validationRecord.SetString(2, columnName);

                                        validationView.Execute(validationRecord);
                                        validationRecord.Close();

                                        if (null != (validationRecord = validationView.Fetch()))
                                        {
                                            string validationNullable = validationRecord.GetString(3);
                                            minValueSet  = !validationRecord.IsNull(4);
                                            minValue     = (minValueSet ? validationRecord.GetInteger(4) : -1);
                                            maxValueSet  = !validationRecord.IsNull(5);
                                            maxValue     = (maxValueSet ? validationRecord.GetInteger(5) : -1);
                                            keyTable     = (!validationRecord.IsNull(6) ? validationRecord.GetString(6) : null);
                                            keyColumnSet = !validationRecord.IsNull(7);
                                            keyColumn    = (keyColumnSet ? validationRecord.GetInteger(7) : -1);
                                            category     = (!validationRecord.IsNull(8) ? validationRecord.GetString(8) : null);
                                            set          = (!validationRecord.IsNull(9) ? validationRecord.GetString(9) : null);
                                            description  = (!validationRecord.IsNull(10) ? validationRecord.GetString(10) : null);

                                            // check the validation nullable value against the column definition
                                            if (null == validationNullable)
                                            {
                                                // TODO: warn for illegal validation nullable column
                                            }
                                            else if ((nullable && "Y" != validationNullable) || (!nullable && "N" != validationNullable))
                                            {
                                                // TODO: warn for mismatch between column definition and validation nullable
                                            }

                                            // convert category to ColumnCategory
                                            if (null != category)
                                            {
                                                try
                                                {
                                                    columnCategory = (ColumnCategory)Enum.Parse(typeof(ColumnCategory), category, true);
                                                }
                                                catch (ArgumentException)
                                                {
                                                    columnCategory = ColumnCategory.Unknown;
                                                }
                                            }

                                            validationRecord.Close();
                                        }
                                        else
                                        {
                                            // TODO: warn about no validation information
                                        }
                                    }

                                    // guess the modularization type
                                    if ("Icon" == keyTable && 1 == keyColumn)
                                    {
                                        columnModularizeType = ColumnModularizeType.Icon;
                                    }
                                    else if ("Condition" == columnName)
                                    {
                                        columnModularizeType = ColumnModularizeType.Condition;
                                    }
                                    else if (ColumnCategory.Formatted == columnCategory)
                                    {
                                        columnModularizeType = ColumnModularizeType.Property;
                                    }
                                    else if (ColumnCategory.Identifier == columnCategory)
                                    {
                                        columnModularizeType = ColumnModularizeType.Column;
                                    }

                                    customTableDefinition.Columns.Add(new ColumnDefinition(columnName, columnType, length, primary, nullable, columnModularizeType, (ColumnType.Localized == columnType), minValueSet, minValue, maxValueSet, maxValue, keyTable, keyColumnSet, keyColumn, columnCategory, set, description, true, true));
                                }

                                tableDefinition = customTableDefinition;

                                customColumnNameRecord.Close();
                                customColumnTypeRecord.Close();
                            }

                            table = new Table(null, tableDefinition);

                            while (null != (rowRecord = tableView.Fetch()))
                            {
                                int recordCount = rowRecord.GetFieldCount();
                                Row row         = table.CreateRow(output.SourceLineNumbers);

                                for (int i = 0; recordCount > i && row.Fields.Length > i; i++)
                                {
                                    if (rowRecord.IsNull(i + 1))
                                    {
                                        if (!row.Fields[i].Column.IsNullable)
                                        {
                                            // TODO: display an error for a null value in a non-nullable field OR
                                            // display a warning and put an empty string in the value to let the compiler handle it
                                            // (the second option is risky because the later code may make certain assumptions about
                                            // the contents of a row value)
                                        }
                                    }
                                    else
                                    {
                                        switch (row.Fields[i].Column.Type)
                                        {
                                        case ColumnType.Number:
                                            if (row.Fields[i].Column.IsLocalizable)
                                            {
                                                row[i] = Convert.ToString(rowRecord.GetInteger(i + 1), CultureInfo.InvariantCulture);
                                            }
                                            else
                                            {
                                                row[i] = rowRecord.GetInteger(i + 1);
                                            }
                                            break;

                                        case ColumnType.Object:
                                            string sourceFile = "FILE NOT EXPORTED, USE THE dark.exe -x OPTION TO EXPORT BINARIES";

                                            if (null != exportBasePath)
                                            {
                                                string relativeSourceFile = Path.Combine(tableName, row.GetPrimaryKey('.'));
                                                sourceFile = Path.Combine(exportBasePath, relativeSourceFile);

                                                // ensure the parent directory exists
                                                System.IO.Directory.CreateDirectory(Path.Combine(exportBasePath, tableName));

                                                using (FileStream fs = System.IO.File.Create(sourceFile))
                                                {
                                                    int    bytesRead;
                                                    byte[] buffer = new byte[512];

                                                    while (0 != (bytesRead = rowRecord.GetStream(i + 1, buffer, buffer.Length)))
                                                    {
                                                        fs.Write(buffer, 0, bytesRead);
                                                    }
                                                }
                                            }

                                            row[i] = sourceFile;
                                            break;

                                        default:
                                            string value = rowRecord.GetString(i + 1);

                                            switch (row.Fields[i].Column.Category)
                                            {
                                            case ColumnCategory.Guid:
                                                value = value.ToUpper(CultureInfo.InvariantCulture);
                                                break;
                                            }

                                            // de-modularize
                                            if (!this.suppressDemodularization && OutputType.Module == output.Type && ColumnModularizeType.None != row.Fields[i].Column.ModularizeType)
                                            {
                                                Regex modularization = new Regex(@"\.[0-9A-Fa-f]{8}_[0-9A-Fa-f]{4}_[0-9A-Fa-f]{4}_[0-9A-Fa-f]{4}_[0-9A-Fa-f]{12}");

                                                if (null == modularizationGuid)
                                                {
                                                    Match match = modularization.Match(value);
                                                    if (match.Success)
                                                    {
                                                        modularizationGuid = String.Concat('{', match.Value.Substring(1).Replace('_', '-'), '}');
                                                    }
                                                }

                                                value = modularization.Replace(value, String.Empty);
                                            }

                                            // escape "$(" for the preprocessor
                                            value = value.Replace("$(", "$$(");

                                            // escape things that look like wix variables
                                            MatchCollection matches = Common.WixVariableRegex.Matches(value);
                                            for (int j = matches.Count - 1; 0 <= j; j--)
                                            {
                                                value = value.Insert(matches[j].Index, "!");
                                            }

                                            row[i] = value;
                                            break;
                                        }
                                    }
                                }

                                rowRecord.Close();
                            }

                            output.Tables.Add(table);
                        }

                        tableRecord.Close();
                    }
                }
            }
            finally
            {
                if (null != validationView)
                {
                    validationView.Close();
                }
            }

            // set the modularization guid as the PackageCode
            if (null != modularizationGuid)
            {
                Table table = output.Tables["_SummaryInformation"];

                foreach (Row row in table.Rows)
                {
                    if (9 == (int)row[0]) // PID_REVNUMBER
                    {
                        row[1] = modularizationGuid;
                    }
                }
            }

            return(output);
        }
예제 #15
0
파일: inscriber.cs 프로젝트: zooba/wix3
        /// <summary>
        /// Updates database with signatures from external cabinets.
        /// </summary>
        /// <param name="databaseFile">Path to MSI database.</param>
        /// <param name="outputFile">Ouput for updated MSI database.</param>
        /// <param name="tidy">Clean up files.</param>
        /// <returns>True if database is updated.</returns>
        public bool InscribeDatabase(string databaseFile, string outputFile, bool tidy)
        {
            // Keeps track of whether we've encountered at least one signed cab or not - we'll throw a warning if no signed cabs were encountered
            bool foundUnsignedExternals = false;
            bool shouldCommit = false;

            FileAttributes attributes = File.GetAttributes(databaseFile);
            if (FileAttributes.ReadOnly == (attributes & FileAttributes.ReadOnly))
            {
                this.OnMessage(WixErrors.ReadOnlyOutputFile(databaseFile));
                return shouldCommit;
            }

            using (Database database = new Database(databaseFile, OpenDatabase.Transact))
            {
                // Just use the English codepage, because the tables we're importing only have binary streams / MSI identifiers / other non-localizable content
                int codepage = 1252;

                // list of certificates for this database (hash/identifier)
                Dictionary<string, string> certificates = new Dictionary<string, string>();

                // Reset the in-memory tables for this new database
                Table digitalSignatureTable = new Table(null, this.tableDefinitions["MsiDigitalSignature"]);
                Table digitalCertificateTable = new Table(null, this.tableDefinitions["MsiDigitalCertificate"]);

                // If any digital signature records exist that are not of the media type, preserve them
                if (database.TableExists("MsiDigitalSignature"))
                {
                    using (View digitalSignatureView = database.OpenExecuteView("SELECT `Table`, `SignObject`, `DigitalCertificate_`, `Hash` FROM `MsiDigitalSignature` WHERE `Table` <> 'Media'"))
                    {
                        while (true)
                        {
                            using (Record digitalSignatureRecord = digitalSignatureView.Fetch())
                            {
                                if (null == digitalSignatureRecord)
                                {
                                    break;
                                }

                                Row digitalSignatureRow = null;
                                digitalSignatureRow = digitalSignatureTable.CreateRow(null);

                                string table = digitalSignatureRecord.GetString(0);
                                string signObject = digitalSignatureRecord.GetString(1);

                                digitalSignatureRow[0] = table;
                                digitalSignatureRow[1] = signObject;
                                digitalSignatureRow[2] = digitalSignatureRecord.GetString(2);

                                if (false == digitalSignatureRecord.IsNull(3))
                                {
                                    // Export to a file, because the MSI API's require us to provide a file path on disk
                                    string hashPath = Path.Combine(this.TempFilesLocation, "MsiDigitalSignature");
                                    string hashFileName = string.Concat(table,".", signObject, ".bin");

                                    Directory.CreateDirectory(hashPath);
                                    hashPath = Path.Combine(hashPath, hashFileName);

                                    using (FileStream fs = File.Create(hashPath))
                                    {
                                        int bytesRead;
                                        byte[] buffer = new byte[1024 * 4];

                                        while (0 != (bytesRead = digitalSignatureRecord.GetStream(3, buffer, buffer.Length)))
                                        {
                                            fs.Write(buffer, 0, bytesRead);
                                        }
                                    }

                                    digitalSignatureRow[3] = hashFileName;
                                }
                            }
                        }
                    }
                }

                // If any digital certificates exist, extract and preserve them
                if (database.TableExists("MsiDigitalCertificate"))
                {
                    using (View digitalCertificateView = database.OpenExecuteView("SELECT * FROM `MsiDigitalCertificate`"))
                    {
                        while (true)
                        {
                            using (Record digitalCertificateRecord = digitalCertificateView.Fetch())
                            {
                                if (null == digitalCertificateRecord)
                                {
                                    break;
                                }

                                string certificateId = digitalCertificateRecord.GetString(1); // get the identifier of the certificate

                                // Export to a file, because the MSI API's require us to provide a file path on disk
                                string certPath = Path.Combine(this.TempFilesLocation, "MsiDigitalCertificate");
                                Directory.CreateDirectory(certPath);
                                certPath = Path.Combine(certPath, string.Concat(certificateId, ".cer"));

                                using (FileStream fs = File.Create(certPath))
                                {
                                    int bytesRead;
                                    byte[] buffer = new byte[1024 * 4];

                                    while (0 != (bytesRead = digitalCertificateRecord.GetStream(2, buffer, buffer.Length)))
                                    {
                                        fs.Write(buffer, 0, bytesRead);
                                    }
                                }

                                // Add it to our "add to MsiDigitalCertificate" table dictionary
                                Row digitalCertificateRow = digitalCertificateTable.CreateRow(null);
                                digitalCertificateRow[0] = certificateId;

                                // Now set the file path on disk where this binary stream will be picked up at import time
                                digitalCertificateRow[1] = string.Concat(certificateId, ".cer");

                                // Load the cert to get it's thumbprint
                                X509Certificate cert = X509Certificate.CreateFromCertFile(certPath);
                                X509Certificate2 cert2 = new X509Certificate2(cert);

                                certificates.Add(cert2.Thumbprint, certificateId);
                            }
                        }
                    }
                }

                using (View mediaView = database.OpenExecuteView("SELECT * FROM `Media`"))
                {
                    while (true)
                    {
                        using (Record mediaRecord = mediaView.Fetch())
                        {
                            if (null == mediaRecord)
                            {
                                break;
                            }

                            X509Certificate2 cert2 = null;
                            Row digitalSignatureRow = null;

                            string cabName = mediaRecord.GetString(4); // get the name of the cab
                            // If there is no cabinet or it's an internal cab, skip it.
                            if (String.IsNullOrEmpty(cabName) || cabName.StartsWith("#", StringComparison.Ordinal))
                            {
                                continue;
                            }

                            string cabId = mediaRecord.GetString(1); // get the ID of the cab
                            string cabPath = Path.Combine(Path.GetDirectoryName(databaseFile), cabName);

                            // If the cabs aren't there, throw an error but continue to catch the other errors
                            if (!File.Exists(cabPath))
                            {
                                this.OnMessage(WixErrors.WixFileNotFound(cabPath));
                                continue;
                            }

                            try
                            {
                                // Get the certificate from the cab
                                X509Certificate signedFileCert = X509Certificate.CreateFromSignedFile(cabPath);
                                cert2 = new X509Certificate2(signedFileCert);
                            }
                            catch (System.Security.Cryptography.CryptographicException e)
                            {
                                uint HResult = unchecked((uint)Marshal.GetHRForException(e));

                                // If the file has no cert, continue, but flag that we found at least one so we can later give a warning
                                if (0x80092009 == HResult) // CRYPT_E_NO_MATCH
                                {
                                    foundUnsignedExternals = true;
                                    continue;
                                }

                                // todo: exactly which HRESULT corresponds to this issue?
                                // If it's one of these exact platforms, warn the user that it may be due to their OS.
                                if ((5 == Environment.OSVersion.Version.Major && 2 == Environment.OSVersion.Version.Minor) || // W2K3
                                        (5 == Environment.OSVersion.Version.Major && 1 == Environment.OSVersion.Version.Minor)) // XP
                                {
                                    this.OnMessage(WixErrors.UnableToGetAuthenticodeCertOfFileDownlevelOS(cabPath, String.Format(CultureInfo.InvariantCulture, "HRESULT: 0x{0:x8}", HResult)));
                                }
                                else // otherwise, generic error
                                {
                                    this.OnMessage(WixErrors.UnableToGetAuthenticodeCertOfFile(cabPath, String.Format(CultureInfo.InvariantCulture, "HRESULT: 0x{0:x8}", HResult)));
                                }
                            }

                            // If we haven't added this cert to the MsiDigitalCertificate table, set it up to be added
                            if (!certificates.ContainsKey(cert2.Thumbprint))
                            {
                                // generate a stable identifier
                                string certificateGeneratedId = Common.GenerateIdentifier("cer", true, cert2.Thumbprint);

                                // Add it to our "add to MsiDigitalCertificate" table dictionary
                                Row digitalCertificateRow = digitalCertificateTable.CreateRow(null);
                                digitalCertificateRow[0] = certificateGeneratedId;

                                // Export to a file, because the MSI API's require us to provide a file path on disk
                                string certPath = Path.Combine(this.TempFilesLocation, "MsiDigitalCertificate");
                                Directory.CreateDirectory(certPath);
                                certPath = Path.Combine(certPath, string.Concat(cert2.Thumbprint, ".cer"));
                                File.Delete(certPath);

                                using (BinaryWriter writer = new BinaryWriter(File.Open(certPath, FileMode.Create)))
                                {
                                    writer.Write(cert2.RawData);
                                    writer.Close();
                                }

                                // Now set the file path on disk where this binary stream will be picked up at import time
                                digitalCertificateRow[1] = string.Concat(cert2.Thumbprint, ".cer");

                                certificates.Add(cert2.Thumbprint, certificateGeneratedId);
                            }

                            digitalSignatureRow = digitalSignatureTable.CreateRow(null);

                            digitalSignatureRow[0] = "Media";
                            digitalSignatureRow[1] = cabId;
                            digitalSignatureRow[2] = certificates[cert2.Thumbprint];
                        }
                    }
                }

                if (digitalCertificateTable.Rows.Count > 0)
                {
                    database.ImportTable(codepage, (IMessageHandler)this, digitalCertificateTable, this.TempFilesLocation, true);
                    shouldCommit = true;
                }

                if (digitalSignatureTable.Rows.Count > 0)
                {
                    database.ImportTable(codepage, (IMessageHandler)this, digitalSignatureTable, this.TempFilesLocation, true);
                    shouldCommit = true;
                }

                // TODO: if we created the table(s), then we should add the _Validation records for them.

                certificates = null;

                // If we did find external cabs but none of them were signed, give a warning
                if (foundUnsignedExternals)
                {
                    this.OnMessage(WixWarnings.ExternalCabsAreNotSigned(databaseFile));
                }

                if (shouldCommit)
                {
                    database.Commit();
                }
            }

            return shouldCommit;
        }
예제 #16
0
파일: Binder.cs 프로젝트: zooba/wix3
        private void SetMsiAssemblyName(Output output, Table assemblyNameTable, FileRow fileRow, string name, string value, IDictionary<string, string> infoCache, string modularizationGuid)
        {
            // check for null value (this can occur when grabbing the file version from an assembly without one)
            if (null == value || 0 == value.Length)
            {
                this.core.OnMessage(WixWarnings.NullMsiAssemblyNameValue(fileRow.SourceLineNumbers, fileRow.Component, name));
            }
            else
            {
                Row assemblyNameRow = null;

                // override directly authored value
                foreach (Row row in assemblyNameTable.Rows)
                {
                    if ((string)row[0] == fileRow.Component && (string)row[1] == name)
                    {
                        assemblyNameRow = row;
                        break;
                    }
                }

                // if the assembly will be GAC'd and the name in the file table doesn't match the name in the MsiAssemblyName table, error because the install will fail.
                if ("name" == name && FileAssemblyType.DotNetAssembly == fileRow.AssemblyType && String.IsNullOrEmpty(fileRow.AssemblyApplication) && !String.Equals(Path.GetFileNameWithoutExtension(fileRow.LongFileName), value, StringComparison.OrdinalIgnoreCase))
                {
                    this.core.OnMessage(WixErrors.GACAssemblyIdentityWarning(fileRow.SourceLineNumbers, Path.GetFileNameWithoutExtension(fileRow.LongFileName), value));
                }

                if (null == assemblyNameRow)
                {
                    assemblyNameRow = assemblyNameTable.CreateRow(fileRow.SourceLineNumbers);
                    assemblyNameRow[0] = fileRow.Component;
                    assemblyNameRow[1] = name;
                    assemblyNameRow[2] = value;

                    // put the MsiAssemblyName row in the same section as the related File row
                    assemblyNameRow.SectionId = fileRow.SectionId;

                    if (null == fileRow.AssemblyNameRows)
                    {
                        fileRow.AssemblyNameRows = new RowCollection();
                    }
                    fileRow.AssemblyNameRows.Add(assemblyNameRow);
                }
                else
                {
                    assemblyNameRow[2] = value;
                }

                if (infoCache != null)
                {
                    string key = String.Format(CultureInfo.InvariantCulture, "assembly{0}.{1}", name, Demodularize(output, modularizationGuid, fileRow.File)).ToLower(CultureInfo.InvariantCulture);
                    infoCache[key] = (string)assemblyNameRow[2];
                }
            }
        }
예제 #17
0
        /// <summary>
        /// Updates database with signatures from external cabinets.
        /// </summary>
        /// <param name="databaseFile">Path to MSI database.</param>
        /// <param name="outputFile">Ouput for updated MSI database.</param>
        /// <param name="tidy">Clean up files.</param>
        /// <returns>True if database is updated.</returns>
        public bool InscribeDatabase(string databaseFile, string outputFile, bool tidy)
        {
            // Keeps track of whether we've encountered at least one signed cab or not - we'll throw a warning if no signed cabs were encountered
            bool foundUnsignedExternals = false;
            bool shouldCommit           = false;

            FileAttributes attributes = File.GetAttributes(databaseFile);

            if (FileAttributes.ReadOnly == (attributes & FileAttributes.ReadOnly))
            {
                this.OnMessage(WixErrors.ReadOnlyOutputFile(databaseFile));
                return(shouldCommit);
            }

            using (Database database = new Database(databaseFile, OpenDatabase.Transact))
            {
                // Just use the English codepage, because the tables we're importing only have binary streams / MSI identifiers / other non-localizable content
                int codepage = 1252;

                // reset list of certificates seen for this database
                Dictionary <string, object> certificates = new Dictionary <string, object>();

                // Reset the in-memory tables for this new database
                Table digitalSignatureTable   = new Table(null, this.tableDefinitions["MsiDigitalSignature"]);
                Table digitalCertificateTable = new Table(null, this.tableDefinitions["MsiDigitalCertificate"]);

                using (View mediaView = database.OpenExecuteView("SELECT * FROM Media"))
                {
                    while (true)
                    {
                        using (Record mediaRecord = mediaView.Fetch())
                        {
                            if (null == mediaRecord)
                            {
                                break;
                            }

                            X509Certificate2 cert2  = null;
                            Row digitalSignatureRow = null;

                            string cabName = mediaRecord.GetString(4); // get the name of the cab
                            // If there is no cabinet or it's an internal cab, skip it.
                            if (String.IsNullOrEmpty(cabName) || cabName.StartsWith("#", StringComparison.Ordinal))
                            {
                                continue;
                            }

                            string cabId   = mediaRecord.GetString(1); // get the ID of the cab
                            string cabPath = Path.Combine(Path.GetDirectoryName(databaseFile), cabName);

                            // If the cabs aren't there, throw an error but continue to catch the other errors
                            if (!File.Exists(cabPath))
                            {
                                this.OnMessage(WixErrors.WixFileNotFound(cabPath));
                                continue;
                            }

                            try
                            {
                                // Get the certificate from the cab
                                X509Certificate signedFileCert = X509Certificate.CreateFromSignedFile(cabPath);
                                cert2 = new X509Certificate2(signedFileCert);
                            }
                            catch (System.Security.Cryptography.CryptographicException e)
                            {
                                uint HResult = unchecked ((uint)Marshal.GetHRForException(e));

                                // If the file has no cert, continue, but flag that we found at least one so we can later give a warning
                                if (0x80092009 == HResult) // CRYPT_E_NO_MATCH
                                {
                                    foundUnsignedExternals = true;
                                    continue;
                                }

                                // todo: exactly which HRESULT corresponds to this issue?
                                // If it's one of these exact platforms, warn the user that it may be due to their OS.
                                if ((5 == Environment.OSVersion.Version.Major && 2 == Environment.OSVersion.Version.Minor) || // W2K3
                                    (5 == Environment.OSVersion.Version.Major && 1 == Environment.OSVersion.Version.Minor))   // XP
                                {
                                    this.OnMessage(WixErrors.UnableToGetAuthenticodeCertOfFileDownlevelOS(cabPath, String.Format(CultureInfo.InvariantCulture, "HRESULT: 0x{0:x8}", HResult)));
                                }
                                else // otherwise, generic error
                                {
                                    this.OnMessage(WixErrors.UnableToGetAuthenticodeCertOfFile(cabPath, String.Format(CultureInfo.InvariantCulture, "HRESULT: 0x{0:x8}", HResult)));
                                }
                            }

                            // If we haven't added this cert to the MsiDigitalCertificate table, set it up to be added
                            if (!certificates.ContainsKey(cert2.Thumbprint))
                            {
                                // Add it to our "add to MsiDigitalCertificate" table dictionary
                                Row digitalCertificateRow = digitalCertificateTable.CreateRow(null);
                                digitalCertificateRow[0] = cert2.Thumbprint;

                                // Export to a file, because the MSI API's require us to provide a file path on disk
                                string certPath = Path.Combine(this.TempFilesLocation, "MsiDigitalCertificate");
                                Directory.CreateDirectory(certPath);
                                certPath = Path.Combine(certPath, cert2.Thumbprint + ".cer");
                                File.Delete(certPath);

                                using (BinaryWriter writer = new BinaryWriter(File.Open(certPath, FileMode.Create)))
                                {
                                    writer.Write(cert2.RawData);
                                    writer.Close();
                                }

                                // Now set the file path on disk where this binary stream will be picked up at import time
                                digitalCertificateRow[1] = cert2.Thumbprint + ".cer";

                                certificates.Add(cert2.Thumbprint, certPath);
                            }

                            digitalSignatureRow = digitalSignatureTable.CreateRow(null);

                            digitalSignatureRow[0] = "Media";
                            digitalSignatureRow[1] = cabId;
                            digitalSignatureRow[2] = cert2.Thumbprint;
                        }
                    }
                }

                if (digitalSignatureTable.Rows.Count > 0)
                {
                    database.ImportTable(codepage, (IMessageHandler)this, digitalSignatureTable, this.TempFilesLocation, true);
                    shouldCommit = true;
                }

                if (digitalCertificateTable.Rows.Count > 0)
                {
                    database.ImportTable(codepage, (IMessageHandler)this, digitalCertificateTable, this.TempFilesLocation, true);
                    shouldCommit = true;
                }

                certificates = null;

                // If we did find external cabs but none of them were signed, give a warning
                if (foundUnsignedExternals)
                {
                    this.OnMessage(WixWarnings.ExternalCabsAreNotSigned(databaseFile));
                }

                if (shouldCommit)
                {
                    database.Commit();
                }
            }

            return(shouldCommit);
        }
예제 #18
0
파일: Unbinder.cs 프로젝트: zooba/wix3
        /// <summary>
        /// Create a deleted or modified row.
        /// </summary>
        /// <param name="table">The table containing the row.</param>
        /// <param name="primaryKeys">The primary keys of the row.</param>
        /// <param name="setRequiredFields">Option to set all required fields with placeholder values.</param>
        /// <returns>The new row.</returns>
        private Row CreateRow(Table table, string primaryKeys, bool setRequiredFields)
        {
            Row row = table.CreateRow(null);

            string[] primaryKeyParts = primaryKeys.Split('\t');
            int primaryKeyPartIndex = 0;

            for (int i = 0; i < table.Definition.Columns.Count; i++)
            {
                ColumnDefinition columnDefinition = table.Definition.Columns[i];

                if (columnDefinition.IsPrimaryKey)
                {
                    if (ColumnType.Number == columnDefinition.Type && !columnDefinition.IsLocalizable)
                    {
                        row[i] = Convert.ToInt32(primaryKeyParts[primaryKeyPartIndex++], CultureInfo.InvariantCulture);
                    }
                    else
                    {
                        row[i] = primaryKeyParts[primaryKeyPartIndex++];
                    }
                }
                else if (setRequiredFields)
                {
                    if (ColumnType.Number == columnDefinition.Type && !columnDefinition.IsLocalizable)
                    {
                        row[i] = 1;
                    }
                    else if (ColumnType.Object == columnDefinition.Type)
                    {
                        if (null == this.emptyFile)
                        {
                            this.emptyFile = this.tempFiles.AddExtension("empty");
                            using (FileStream fileStream = File.Create(this.emptyFile))
                            {
                            }
                        }

                        row[i] = this.emptyFile;
                    }
                    else
                    {
                        row[i] = "1";
                    }
                }
            }

            return row;
        }
예제 #19
0
파일: Row.cs 프로젝트: bleissem/wix3
        /// <summary>
        /// Creates a Row from the XmlReader.
        /// </summary>
        /// <param name="reader">Reader to get data from.</param>
        /// <param name="table">Table for this row.</param>
        /// <returns>New row object.</returns>
        internal static Row Parse(XmlReader reader, Table table)
        {
            Debug.Assert("row" == reader.LocalName);

            bool empty = reader.IsEmptyElement;
            RowOperation operation = RowOperation.None;
            string sectionId = null;
            SourceLineNumberCollection sourceLineNumbers = null;

            while (reader.MoveToNextAttribute())
            {
                switch (reader.LocalName)
                {
                    case "op":
                        switch (reader.Value)
                        {
                            case "add":
                                operation = RowOperation.Add;
                                break;
                            case "delete":
                                operation = RowOperation.Delete;
                                break;
                            case "modify":
                                operation = RowOperation.Modify;
                                break;
                            default:
                                throw new WixException(WixErrors.IllegalAttributeValue(SourceLineNumberCollection.FromUri(reader.BaseURI), "row", reader.Name, reader.Value, "Add", "Delete", "Modify"));
                        }
                        break;
                    case "sectionId":
                        sectionId = reader.Value;
                        break;
                    case "sourceLineNumber":
                        sourceLineNumbers = new SourceLineNumberCollection(reader.Value);
                        break;
                    default:
                        if (!reader.NamespaceURI.StartsWith("http://www.w3.org/", StringComparison.Ordinal))
                        {
                            throw new WixException(WixErrors.UnexpectedAttribute(SourceLineNumberCollection.FromUri(reader.BaseURI), "row", reader.Name));
                        }
                        break;
                }
            }

            Row row = table.CreateRow(sourceLineNumbers);
            row.Operation = operation;
            row.SectionId = sectionId;

            // loop through all the fields in a row
            if (!empty)
            {
                bool done = false;
                int field = 0;

                // loop through all the fields in a row
                while (!done && reader.Read())
                {
                    switch (reader.NodeType)
                    {
                        case XmlNodeType.Element:
                            switch (reader.LocalName)
                            {
                                case "field":
                                    if (row.Fields.Length <= field)
                                    {
                                        if (!reader.IsEmptyElement)
                                        {
                                            throw new WixException(WixErrors.UnexpectedColumnCount(SourceLineNumberCollection.FromUri(reader.BaseURI), table.Name));
                                        }
                                    }
                                    else
                                    {
                                        row.fields[field].Parse(reader);
                                    }
                                    ++field;
                                    break;
                                default:
                                    throw new WixException(WixErrors.UnexpectedElement(SourceLineNumberCollection.FromUri(reader.BaseURI), "row", reader.Name));
                            }
                            break;
                        case XmlNodeType.EndElement:
                            done = true;
                            break;
                    }
                }

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

            return row;
        }
예제 #20
0
파일: Unbinder.cs 프로젝트: zooba/wix3
        /// <summary>
        /// Unbind an MSI database file.
        /// </summary>
        /// <param name="databaseFile">The database file.</param>
        /// <param name="database">The opened database.</param>
        /// <param name="outputType">The type of output to create.</param>
        /// <param name="exportBasePath">The path where files should be exported.</param>
        /// <param name="skipSummaryInfo">Option to skip unbinding the _SummaryInformation table.</param>
        /// <returns>The output representing the database.</returns>
        private Output UnbindDatabase(string databaseFile, Database database, OutputType outputType, string exportBasePath, bool skipSummaryInfo)
        {
            string modularizationGuid = null;
            Output output = new Output(SourceLineNumberCollection.FromFileName(databaseFile));
            View validationView = null;

            // set the output type
            output.Type = outputType;

            // get the codepage
            database.Export("_ForceCodepage", this.TempFilesLocation, "_ForceCodepage.idt");
            using (StreamReader sr = File.OpenText(Path.Combine(this.TempFilesLocation, "_ForceCodepage.idt")))
            {
                string line;

                while (null != (line = sr.ReadLine()))
                {
                    string[] data = line.Split('\t');

                    if (2 == data.Length)
                    {
                        output.Codepage = Convert.ToInt32(data[0], CultureInfo.InvariantCulture);
                    }
                }
            }

            // get the summary information table if it exists; it won't if unbinding a transform
            if (!skipSummaryInfo)
            {
                using (SummaryInformation summaryInformation = new SummaryInformation(database))
                {
                    Table table = new Table(null, this.tableDefinitions["_SummaryInformation"]);

                    for (int i = 1; 19 >= i; i++)
                    {
                        string value = summaryInformation.GetProperty(i);

                        if (0 < value.Length)
                        {
                            Row row = table.CreateRow(output.SourceLineNumbers);
                            row[0] = i;
                            row[1] = value;
                        }
                    }

                    output.Tables.Add(table);
                }
            }

            try
            {
                // open a view on the validation table if it exists
                if (database.TableExists("_Validation"))
                {
                    validationView = database.OpenView("SELECT * FROM `_Validation` WHERE `Table` = ? AND `Column` = ?");
                }

                // get the normal tables
                using (View tablesView = database.OpenExecuteView("SELECT * FROM _Tables"))
                {
                    while (true)
                    {
                        using (Record tableRecord = tablesView.Fetch())
                        {
                            if (null == tableRecord)
                            {
                                break;
                            }

                            string tableName = tableRecord.GetString(1);

                            using (View tableView = database.OpenExecuteView(String.Format(CultureInfo.InvariantCulture, "SELECT * FROM `{0}`", tableName)))
                            {
                                TableDefinition tableDefinition = new TableDefinition(tableName, false, false);
                                Hashtable tablePrimaryKeys = new Hashtable();

                                using (Record columnNameRecord = tableView.GetColumnInfo(MsiInterop.MSICOLINFONAMES),
                                              columnTypeRecord = tableView.GetColumnInfo(MsiInterop.MSICOLINFOTYPES))
                                {
                                    int columnCount = columnNameRecord.GetFieldCount();

                                    // index the primary keys
                                    using (Record primaryKeysRecord = database.PrimaryKeys(tableName))
                                    {
                                        int primaryKeysFieldCount = primaryKeysRecord.GetFieldCount();

                                        for (int i = 1; i <= primaryKeysFieldCount; i++)
                                        {
                                            tablePrimaryKeys[primaryKeysRecord.GetString(i)] = null;
                                        }
                                    }

                                    for (int i = 1; i <= columnCount; i++)
                                    {
                                        string columnName = columnNameRecord.GetString(i);
                                        string idtType = columnTypeRecord.GetString(i);

                                        ColumnType columnType;
                                        int length;
                                        bool nullable;

                                        ColumnCategory columnCategory = ColumnCategory.Unknown;
                                        ColumnModularizeType columnModularizeType = ColumnModularizeType.None;
                                        bool primary = tablePrimaryKeys.Contains(columnName);
                                        bool minValueSet = false;
                                        int minValue = -1;
                                        bool maxValueSet = false;
                                        int maxValue = -1;
                                        string keyTable = null;
                                        bool keyColumnSet = false;
                                        int keyColumn = -1;
                                        string category = null;
                                        string set = null;
                                        string description = null;

                                        // get the column type, length, and whether its nullable
                                        switch (Char.ToLower(idtType[0], CultureInfo.InvariantCulture))
                                        {
                                            case 'i':
                                                columnType = ColumnType.Number;
                                                break;
                                            case 'l':
                                                columnType = ColumnType.Localized;
                                                break;
                                            case 's':
                                                columnType = ColumnType.String;
                                                break;
                                            case 'v':
                                                columnType = ColumnType.Object;
                                                break;
                                            default:
                                                // TODO: error
                                                columnType = ColumnType.Unknown;
                                                break;
                                        }
                                        length = Convert.ToInt32(idtType.Substring(1), CultureInfo.InvariantCulture);
                                        nullable = Char.IsUpper(idtType[0]);

                                        // try to get validation information
                                        if (null != validationView)
                                        {
                                            using (Record validationRecord = new Record(2))
                                            {
                                                validationRecord.SetString(1, tableName);
                                                validationRecord.SetString(2, columnName);

                                                validationView.Execute(validationRecord);
                                            }

                                            using (Record validationRecord = validationView.Fetch())
                                            {
                                                if (null != validationRecord)
                                                {
                                                    string validationNullable = validationRecord.GetString(3);
                                                    minValueSet = !validationRecord.IsNull(4);
                                                    minValue = (minValueSet ? validationRecord.GetInteger(4) : -1);
                                                    maxValueSet = !validationRecord.IsNull(5);
                                                    maxValue = (maxValueSet ? validationRecord.GetInteger(5) : -1);
                                                    keyTable = (!validationRecord.IsNull(6) ? validationRecord.GetString(6) : null);
                                                    keyColumnSet = !validationRecord.IsNull(7);
                                                    keyColumn = (keyColumnSet ? validationRecord.GetInteger(7) : -1);
                                                    category = (!validationRecord.IsNull(8) ? validationRecord.GetString(8) : null);
                                                    set = (!validationRecord.IsNull(9) ? validationRecord.GetString(9) : null);
                                                    description = (!validationRecord.IsNull(10) ? validationRecord.GetString(10) : null);

                                                    // check the validation nullable value against the column definition
                                                    if (null == validationNullable)
                                                    {
                                                        // TODO: warn for illegal validation nullable column
                                                    }
                                                    else if ((nullable && "Y" != validationNullable) || (!nullable && "N" != validationNullable))
                                                    {
                                                        // TODO: warn for mismatch between column definition and validation nullable
                                                    }

                                                    // convert category to ColumnCategory
                                                    if (null != category)
                                                    {
                                                        try
                                                        {
                                                            columnCategory = (ColumnCategory)Enum.Parse(typeof(ColumnCategory), category, true);
                                                        }
                                                        catch (ArgumentException)
                                                        {
                                                            columnCategory = ColumnCategory.Unknown;
                                                        }
                                                    }
                                                }
                                                else
                                                {
                                                    // TODO: warn about no validation information
                                                }
                                            }
                                        }

                                        // guess the modularization type
                                        if ("Icon" == keyTable && 1 == keyColumn)
                                        {
                                            columnModularizeType = ColumnModularizeType.Icon;
                                        }
                                        else if ("Condition" == columnName)
                                        {
                                            columnModularizeType = ColumnModularizeType.Condition;
                                        }
                                        else if (ColumnCategory.Formatted == columnCategory || ColumnCategory.FormattedSDDLText == columnCategory)
                                        {
                                            columnModularizeType = ColumnModularizeType.Property;
                                        }
                                        else if (ColumnCategory.Identifier == columnCategory)
                                        {
                                            columnModularizeType = ColumnModularizeType.Column;
                                        }

                                        tableDefinition.Columns.Add(new ColumnDefinition(columnName, columnType, length, primary, nullable, columnModularizeType, (ColumnType.Localized == columnType), minValueSet, minValue, maxValueSet, maxValue, keyTable, keyColumnSet, keyColumn, columnCategory, set, description, true, true));
                                    }
                                }
                                // use our table definitions if core properties are the same; this allows us to take advantage
                                // of wix concepts like localizable columns which current code assumes
                                if (this.tableDefinitions.Contains(tableName) && 0 == tableDefinition.CompareTo(this.tableDefinitions[tableName]))
                                {
                                    tableDefinition = this.tableDefinitions[tableName];
                                }
                                Table table = new Table(null, tableDefinition);

                                while (true)
                                {
                                    using (Record rowRecord = tableView.Fetch())
                                    {
                                        if (null == rowRecord)
                                        {
                                            break;
                                        }

                                        int recordCount = rowRecord.GetFieldCount();
                                        Row row = table.CreateRow(output.SourceLineNumbers);

                                        for (int i = 0; recordCount > i && row.Fields.Length > i; i++)
                                        {
                                            if (rowRecord.IsNull(i + 1))
                                            {
                                                if (!row.Fields[i].Column.IsNullable)
                                                {
                                                    // TODO: display an error for a null value in a non-nullable field OR
                                                    // display a warning and put an empty string in the value to let the compiler handle it
                                                    // (the second option is risky because the later code may make certain assumptions about
                                                    // the contents of a row value)
                                                }
                                            }
                                            else
                                            {
                                                switch (row.Fields[i].Column.Type)
                                                {
                                                    case ColumnType.Number:
                                                        bool success = false;
                                                        int intValue = rowRecord.GetInteger(i + 1);
                                                        if (row.Fields[i].Column.IsLocalizable)
                                                        {
                                                            success = row.BestEffortSetField(i, Convert.ToString(intValue, CultureInfo.InvariantCulture));
                                                        }
                                                        else
                                                        {
                                                            success = row.BestEffortSetField(i, intValue);
                                                        }

                                                        if (!success)
                                                        {
                                                            this.OnMessage(WixWarnings.BadColumnDataIgnored(row.SourceLineNumbers, Convert.ToString(intValue, CultureInfo.InvariantCulture), tableName, row.Fields[i].Column.Name));
                                                        }
                                                        break;
                                                    case ColumnType.Object:
                                                        string sourceFile = "FILE NOT EXPORTED, USE THE dark.exe -x OPTION TO EXPORT BINARIES";

                                                        if (null != exportBasePath)
                                                        {
                                                            string relativeSourceFile = Path.Combine(tableName, row.GetPrimaryKey('.'));
                                                            sourceFile = Path.Combine(exportBasePath, relativeSourceFile);

                                                            // ensure the parent directory exists
                                                            System.IO.Directory.CreateDirectory(Path.Combine(exportBasePath, tableName));

                                                            using (FileStream fs = System.IO.File.Create(sourceFile))
                                                            {
                                                                int bytesRead;
                                                                byte[] buffer = new byte[512];

                                                                while (0 != (bytesRead = rowRecord.GetStream(i + 1, buffer, buffer.Length)))
                                                                {
                                                                    fs.Write(buffer, 0, bytesRead);
                                                                }
                                                            }
                                                        }

                                                        row[i] = sourceFile;
                                                        break;
                                                    default:
                                                        string value = rowRecord.GetString(i + 1);

                                                        switch (row.Fields[i].Column.Category)
                                                        {
                                                            case ColumnCategory.Guid:
                                                                value = value.ToUpper(CultureInfo.InvariantCulture);
                                                                break;
                                                        }

                                                        // de-modularize
                                                        if (!this.suppressDemodularization && OutputType.Module == output.Type && ColumnModularizeType.None != row.Fields[i].Column.ModularizeType)
                                                        {
                                                            Regex modularization = new Regex(@"\.[0-9A-Fa-f]{8}_[0-9A-Fa-f]{4}_[0-9A-Fa-f]{4}_[0-9A-Fa-f]{4}_[0-9A-Fa-f]{12}");

                                                            if (null == modularizationGuid)
                                                            {
                                                                Match match = modularization.Match(value);
                                                                if (match.Success)
                                                                {
                                                                    modularizationGuid = String.Concat('{', match.Value.Substring(1).Replace('_', '-'), '}');
                                                                }
                                                            }

                                                            value = modularization.Replace(value, String.Empty);
                                                        }

                                                        // escape "$(" for the preprocessor
                                                        value = value.Replace("$(", "$$(");

                                                        // escape things that look like wix variables
                                                        MatchCollection matches = Common.WixVariableRegex.Matches(value);
                                                        for (int j = matches.Count - 1; 0 <= j; j--)
                                                        {
                                                            value = value.Insert(matches[j].Index, "!");
                                                        }

                                                        row[i] = value;
                                                        break;
                                                }
                                            }
                                        }
                                    }
                                }

                                output.Tables.Add(table);
                            }

                        }
                    }
                }
            }
            finally
            {
                if (null != validationView)
                {
                    validationView.Close();
                }
            }

            // set the modularization guid as the PackageCode
            if (null != modularizationGuid)
            {
                Table table = output.Tables["_SummaryInformation"];

                foreach (Row row in table.Rows)
                {
                    if (9 == (int)row[0]) // PID_REVNUMBER
                    {
                        row[1] = modularizationGuid;
                    }
                }
            }

            if (this.isAdminImage)
            {
                GenerateWixFileTable(databaseFile, output);
                GenerateSectionIds(output);
            }

            return output;
        }
예제 #21
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(Table mediaTable, int cabIndex, string compressionLevel)
        {
            MediaRow currentMediaRow = (MediaRow)mediaTable.CreateRow(null);
            currentMediaRow.DiskId = cabIndex;
            currentMediaRow.Cabinet = String.Format(this.cabinetNameTemplate, cabIndex);
            this.mediaRows.Add(currentMediaRow);
            this.cabinets.Add(currentMediaRow, new FileRowCollection());

            Table wixMediaTable = this.output.EnsureTable(this.core.TableDefinitions["WixMedia"]);
            Row row = wixMediaTable.CreateRow(null);
            row[0] = cabIndex;
            row[1] = compressionLevel;

            return currentMediaRow;
        }
예제 #22
0
        /// <summary>
        /// Assigne files to cabinets based on MediaTemplate authoring.
        /// </summary>
        /// <param name="fileRows">FileRowCollection</param>
        private void AutoAssignFiles(Table mediaTable, FileRowCollection fileRows)
        {
            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 (FileRow fileRow in fileRows)
            {
                // 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 == output.Type &&
                    (YesNoType.No == fileRow.Compressed ||
                    (YesNoType.NotSet == fileRow.Compressed && !this.filesCompressed)))
                {
                    uncompressedFileRows.Add(fileRow);
                    continue;
                }

                FileInfo fileInfo = null;

                // Get the file size
                try
                {
                    fileInfo = new FileInfo(fileRow.Source);
                }
                catch (ArgumentException)
                {
                    this.core.OnMessage(WixErrors.InvalidFileName(fileRow.SourceLineNumbers, fileRow.Source));
                }
                catch (PathTooLongException)
                {
                    this.core.OnMessage(WixErrors.InvalidFileName(fileRow.SourceLineNumbers, fileRow.Source));
                }
                catch (NotSupportedException)
                {
                    this.core.OnMessage(WixErrors.InvalidFileName(fileRow.SourceLineNumbers, fileRow.Source));
                }

                if (fileInfo.Exists)
                {
                    if (fileInfo.Length > Int32.MaxValue)
                    {
                        throw new WixException(WixErrors.FileTooLarge(fileRow.SourceLineNumbers, fileRow.Source));
                    }

                    fileRow.FileSize = Convert.ToInt32(fileInfo.Length, CultureInfo.InvariantCulture);
                }

                if (currentCabIndex == MaxCabIndex)
                {
                    // Associate current file with last cab (irrespective of the size) and cab index is not incremented anymore.
                    FileRowCollection cabinetFileRow = (FileRowCollection)this.cabinets[currentMediaRow];
                    fileRow.DiskId = currentCabIndex;
                    cabinetFileRow.Add(fileRow);
                    continue;
                }

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

                if (currentPreCabSize > maxPreCabSizeInBytes)
                {
                    // Overflow due to current file
                    if (currentPreCabSize == (ulong)fileRow.FileSize)
                    {
                        // Only one file in this cab.
                        currentMediaRow = AddMediaRow(mediaTable, ++currentCabIndex);

                        FileRowCollection cabinetFileRow = (FileRowCollection)cabinets[currentMediaRow];
                        fileRow.DiskId = currentCabIndex;
                        cabinetFileRow.Add(fileRow);
                        currentPreCabSize = 0;
                    }
                    else
                    {
                        currentMediaRow = this.AddMediaRow(mediaTable, ++currentCabIndex);

                        // Finish current media row and create new one.
                        FileRowCollection cabinetFileRow = (FileRowCollection)this.cabinets[currentMediaRow];
                        fileRow.DiskId = currentCabIndex;
                        cabinetFileRow.Add(fileRow);
                        currentPreCabSize = (ulong)fileRow.FileSize;
                    }
                }
                else
                {
                    // File fits in the current cab.
                    if (currentMediaRow == null)
                    {
                        // Create new cab and MediaRow
                        currentMediaRow = AddMediaRow(mediaTable, ++currentCabIndex);
                    }

                    // Associate current file with current cab.
                    FileRowCollection cabinetFileRow = (FileRowCollection)this.cabinets[currentMediaRow];
                    fileRow.DiskId = currentCabIndex;
                    cabinetFileRow.Add(fileRow);
                }
            }

            // If there are uncompressed files and no MediaRow, create a default one.
            if (uncompressedFileRows.Count > 0 && mediaTable.Rows.Count == 0 )
            {
                 MediaRow defaultMediaRow = (MediaRow)mediaTable.CreateRow(null);
                 defaultMediaRow.DiskId = 1;
                 mediaRows.Add(defaultMediaRow);
            }
        }
예제 #23
0
파일: Differ.cs 프로젝트: Jeremiahf/wix3
        private void UpdateTransformSummaryInformationTable(Table summaryInfoTable, TransformFlags validationFlags)
        {
            // calculate the minimum version of MSI required to process the transform
            int targetMin;
            int updatedMin;
            int minimumVersion = 100;

            if (Int32.TryParse(this.transformSummaryInfo.TargetMinimumVersion, out targetMin) && Int32.TryParse(this.transformSummaryInfo.UpdatedMinimumVersion, out updatedMin))
            {
                minimumVersion = Math.Max(targetMin, updatedMin);
            }

            Hashtable summaryRows = new Hashtable(summaryInfoTable.Rows.Count);
            foreach (Row row in summaryInfoTable.Rows)
            {
                summaryRows[row[0]] = row;

                if ((int)SummaryInformation.Transform.CodePage == (int)row[0])
                {
                    row.Fields[1].Data = this.transformSummaryInfo.UpdatedSummaryInfoCodepage;
                    row.Fields[1].PreviousData = this.transformSummaryInfo.TargetSummaryInfoCodepage;
                }
                else if ((int)SummaryInformation.Transform.TargetPlatformAndLanguage == (int)row[0])
                {
                    row[1] = this.transformSummaryInfo.TargetPlatformAndLanguage;
                }
                else if ((int)SummaryInformation.Transform.UpdatedPlatformAndLanguage == (int)row[0])
                {
                    row[1] = this.transformSummaryInfo.UpdatedPlatformAndLanguage;
                }
                else if ((int)SummaryInformation.Transform.ProductCodes == (int)row[0])
                {
                    row[1] = String.Concat(this.transformSummaryInfo.TargetProductCode, this.transformSummaryInfo.TargetProductVersion, ';', this.transformSummaryInfo.UpdatedProductCode, this.transformSummaryInfo.UpdatedProductVersion, ';', this.transformSummaryInfo.TargetUpgradeCode);
                }
                else if ((int)SummaryInformation.Transform.InstallerRequirement == (int)row[0])
                {
                    row[1] = minimumVersion.ToString(CultureInfo.InvariantCulture);
                }
                else if ((int)SummaryInformation.Transform.Security == (int)row[0])
                {
                    row[1] = "4";
                }
            }

            if (!summaryRows.Contains((int)SummaryInformation.Transform.TargetPlatformAndLanguage))
            {
                Row summaryRow = summaryInfoTable.CreateRow(null);
                summaryRow[0] = (int)SummaryInformation.Transform.TargetPlatformAndLanguage;
                summaryRow[1] = this.transformSummaryInfo.TargetPlatformAndLanguage;
            }

            if (!summaryRows.Contains((int)SummaryInformation.Transform.UpdatedPlatformAndLanguage))
            {
                Row summaryRow = summaryInfoTable.CreateRow(null);
                summaryRow[0] = (int)SummaryInformation.Transform.UpdatedPlatformAndLanguage;
                summaryRow[1] = this.transformSummaryInfo.UpdatedPlatformAndLanguage;
            }

            if (!summaryRows.Contains((int)SummaryInformation.Transform.ValidationFlags))
            {
                Row summaryRow = summaryInfoTable.CreateRow(null);
                summaryRow[0] = (int)SummaryInformation.Transform.ValidationFlags;
                summaryRow[1] = ((int)validationFlags).ToString(CultureInfo.InvariantCulture);
            }

            if (!summaryRows.Contains((int)SummaryInformation.Transform.InstallerRequirement))
            {
                Row summaryRow = summaryInfoTable.CreateRow(null);
                summaryRow[0] = (int)SummaryInformation.Transform.InstallerRequirement;
                summaryRow[1] = minimumVersion.ToString(CultureInfo.InvariantCulture);
            }

            if (!summaryRows.Contains((int)SummaryInformation.Transform.Security))
            {
                Row summaryRow = summaryInfoTable.CreateRow(null);
                summaryRow[0] = (int)SummaryInformation.Transform.Security;
                summaryRow[1] = "4";
            }
        }
예제 #24
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(Table mediaTable, int cabIndex)
 {
     MediaRow currentMediaRow = (MediaRow)mediaTable.CreateRow(null);
     currentMediaRow.DiskId = cabIndex;
     mediaRows.Add(currentMediaRow);
     currentMediaRow.Cabinet = String.Format(this.cabinetNameTemplate, cabIndex);
     cabinets.Add(currentMediaRow, new FileRowCollection());
     return currentMediaRow;
 }
예제 #25
0
        /// <summary>
        /// Creates a Row from the XmlReader.
        /// </summary>
        /// <param name="reader">Reader to get data from.</param>
        /// <param name="table">Table for this row.</param>
        /// <returns>New row object.</returns>
        internal static Row Parse(XmlReader reader, Table table)
        {
            Debug.Assert("row" == reader.LocalName);

            bool         empty     = reader.IsEmptyElement;
            RowOperation operation = RowOperation.None;
            string       sectionId = null;
            SourceLineNumberCollection sourceLineNumbers = null;

            while (reader.MoveToNextAttribute())
            {
                switch (reader.LocalName)
                {
                case "op":
                    switch (reader.Value)
                    {
                    case "add":
                        operation = RowOperation.Add;
                        break;

                    case "delete":
                        operation = RowOperation.Delete;
                        break;

                    case "modify":
                        operation = RowOperation.Modify;
                        break;

                    default:
                        throw new WixException(WixErrors.IllegalAttributeValue(SourceLineNumberCollection.FromUri(reader.BaseURI), "row", reader.Name, reader.Value, "Add", "Delete", "Modify"));
                    }
                    break;

                case "sectionId":
                    sectionId = reader.Value;
                    break;

                case "sourceLineNumber":
                    sourceLineNumbers = new SourceLineNumberCollection(reader.Value);
                    break;

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

            Row row = table.CreateRow(sourceLineNumbers);

            row.Operation = operation;
            row.SectionId = sectionId;

            // loop through all the fields in a row
            if (!empty)
            {
                bool done  = false;
                int  field = 0;

                // loop through all the fields in a row
                while (!done && reader.Read())
                {
                    switch (reader.NodeType)
                    {
                    case XmlNodeType.Element:
                        switch (reader.LocalName)
                        {
                        case "field":
                            if (row.Fields.Length <= field)
                            {
                                if (!reader.IsEmptyElement)
                                {
                                    throw new WixException(WixErrors.UnexpectedColumnCount(SourceLineNumberCollection.FromUri(reader.BaseURI), table.Name));
                                }
                            }
                            else
                            {
                                row.fields[field].Parse(reader);
                            }
                            ++field;
                            break;

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

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

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

            return(row);
        }
예제 #26
0
        /// <summary>
        /// Include transforms in a patch.
        /// </summary>
        /// <param name="transforms">List of transforms to attach.</param>
        public void AttachTransforms(ArrayList transforms)
        {
            int emptyTransform = 0;

            if (transforms == null || transforms.Count == 0)
            {
                throw new WixException(WixErrors.PatchWithoutTransforms());
            }

            // Get the patch id from the WixPatchId table.
            string patchId         = null;
            Table  wixPatchIdTable = this.patch.Tables["WixPatchId"];

            if (null != wixPatchIdTable && 0 < wixPatchIdTable.Rows.Count)
            {
                Row patchIdRow = wixPatchIdTable.Rows[0];
                if (null != patchIdRow)
                {
                    patchId = patchIdRow[0].ToString();
                }
            }

            // enumerate patch.Media to map diskId to Media row
            Hashtable mediaRows       = new Hashtable();
            Table     patchMediaTable = patch.Tables["Media"];

            if (patchMediaTable != null)
            {
                foreach (MediaRow row in patchMediaTable.Rows)
                {
                    int media = row.DiskId;
                    mediaRows[media] = row;
                }
            }

            // enumerate patch.WixPatchBaseline to map baseline to diskId
            Hashtable baselineMedia      = new Hashtable();
            Table     patchBaselineTable = patch.Tables["WixPatchBaseline"];

            if (patchBaselineTable != null)
            {
                foreach (Row row in patchBaselineTable.Rows)
                {
                    string baseline = (string)row[0];
                    int    media    = (int)row[1];
                    if (baselineMedia.Contains(baseline))
                    {
                        throw new InvalidOperationException(String.Format("PatchBaseline '{0}' authored into multiple Media.", baseline));
                    }
                    baselineMedia[baseline] = media;
                }
            }

            // enumerate transforms
            ArrayList productCodes   = new ArrayList();
            ArrayList transformNames = new ArrayList();
            int       transformCount = 0;

            foreach (PatchTransform mainTransform in transforms)
            {
                string baseline = null;
                int    media    = -1;

                if (baselineMedia.Contains(mainTransform.Baseline))
                {
                    int newMedia = (int)baselineMedia[mainTransform.Baseline];
                    if (media != -1 && media != newMedia)
                    {
                        throw new InvalidOperationException(String.Format("Transform authored into multiple Media '{0}' and '{1}'.", media, newMedia));
                    }
                    baseline = mainTransform.Baseline;
                    media    = newMedia;
                }

                if (media == -1)
                {
                    // transform's baseline not attached to any Media
                    continue;
                }

                Table patchRefTable = patch.Tables["WixPatchRef"];
                if (patchRefTable != null && patchRefTable.Rows.Count > 0)
                {
                    if (!this.ReduceTransform(mainTransform.Transform, patchRefTable))
                    {
                        // transform has none of the content authored into this patch
                        emptyTransform++;
                        continue;
                    }
                }

                // ensure consistent File.Sequence within each Media
                MediaRow mediaRow = (MediaRow)mediaRows[media];
                // TODO: should this be authored rather than inferring it from DiskId?
                mediaRow.LastSequence = mediaRow.DiskId;

                // ignore media table from transform.
                mainTransform.Transform.Tables.Remove("Media");
                mainTransform.Transform.Tables.Remove("WixMedia");
                mainTransform.Transform.Tables.Remove("MsiDigitalSignature");

                string productCode     = null;
                Output pairedTransform = this.BuildPairedTransform(patchId, mainTransform.Transform, mediaRow, ref productCode);
                productCodes.Add(productCode);

                // attach these transforms to the patch object
                // TODO: is this an acceptable way to auto-generate transform stream names?
                string transformName = baseline + "." + (++transformCount).ToString();
                patch.SubStorages.Add(new SubStorage(transformName, mainTransform.Transform));
                patch.SubStorages.Add(new SubStorage("#" + transformName, pairedTransform));
                transformNames.Add(":" + transformName);
                transformNames.Add(":#" + transformName);
            }

            if (emptyTransform == transforms.Count)
            {
                throw new WixException(WixErrors.PatchWithoutValidTransforms());
            }

            // populate MSP summary information
            Table patchSummaryInfo = patch.EnsureTable(this.tableDefinitions["_SummaryInformation"]);

            // remove any existing data for these fields
            for (int i = patchSummaryInfo.Rows.Count - 1; i >= 0; i--)
            {
                Row row = patchSummaryInfo.Rows[i];
                switch ((SummaryInformation.Patch)row[0])
                {
                case SummaryInformation.Patch.ProductCodes:
                case SummaryInformation.Patch.TransformNames:
                case SummaryInformation.Patch.PatchCode:
                case SummaryInformation.Patch.InstallerRequirement:
                    patchSummaryInfo.Rows.RemoveAt(i);
                    break;
                }
            }

            // Semicolon delimited list of the product codes that can accept the patch.
            Row templateRow = patchSummaryInfo.CreateRow(null);

            templateRow[0] = (int)SummaryInformation.Patch.ProductCodes;
            templateRow[1] = String.Join(";", (string[])productCodes.ToArray(typeof(string)));

            // Semicolon delimited list of transform substorage names in the order they are applied.
            Row savedbyRow = patchSummaryInfo.CreateRow(null);

            savedbyRow[0] = (int)SummaryInformation.Patch.TransformNames;
            savedbyRow[1] = String.Join(";", (string[])transformNames.ToArray(typeof(string)));

            // GUID patch code for the patch.
            Row revisionRow = patchSummaryInfo.CreateRow(null);

            revisionRow[0] = (int)SummaryInformation.Patch.PatchCode;
            revisionRow[1] = patchId;

            // Indicates the minimum Windows Installer version that is required to install the patch.
            Row wordsRow = patchSummaryInfo.CreateRow(null);

            wordsRow[0] = (int)SummaryInformation.Patch.InstallerRequirement;
            wordsRow[1] = ((int)SummaryInformation.InstallerRequirement.Version31).ToString();

            Row security = patchSummaryInfo.CreateRow(null);

            security[0] = 19; //PID_SECURITY
            security[1] = "4";

            Table msiPatchMetadataTable = patch.Tables["MsiPatchMetadata"];

            if (null != msiPatchMetadataTable)
            {
                Hashtable metadataTable = new Hashtable();
                foreach (Row row in msiPatchMetadataTable.Rows)
                {
                    metadataTable.Add(row.Fields[1].Data.ToString(), row.Fields[2].Data.ToString());
                }

                if (metadataTable.Contains("DisplayName"))
                {
                    string comment = String.Concat("This patch contains the logic and data required to install ", metadataTable["DisplayName"]);

                    Row title = patchSummaryInfo.CreateRow(null);
                    title[0] = 2; //PID_TITLE
                    title[1] = metadataTable["DisplayName"];

                    Row comments = patchSummaryInfo.CreateRow(null);
                    comments[0] = 6; //PID_COMMENTS
                    comments[1] = comment;
                }

                if (metadataTable.Contains("CodePage"))
                {
                    Row codePage = patchSummaryInfo.CreateRow(null);
                    codePage[0] = 1; //PID_CODEPAGE
                    codePage[1] = metadataTable["CodePage"];
                }

                if (metadataTable.Contains("Description"))
                {
                    Row subject = patchSummaryInfo.CreateRow(null);
                    subject[0] = 3; //PID_SUBJECT
                    subject[1] = metadataTable["Description"];
                }

                if (metadataTable.Contains("ManufacturerName"))
                {
                    Row author = patchSummaryInfo.CreateRow(null);
                    author[0] = 4; //PID_AUTHOR
                    author[1] = metadataTable["ManufacturerName"];
                }
            }
        }