Exemplo n.º 1
0
        public void AttachTransforms(ArrayList transforms)
        {
            InspectorCore inspectorCore = new InspectorCore(this.Message);

            // Track if at least one transform gets attached.
            bool attachedTransform = false;

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

            // Get the patch id from the WixPatchId table.
            string patchId = null;
            string clientPatchId = 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();
                    clientPatchId = patchIdRow[1].ToString();
                }
            }

            if (null == patchId)
            {
                throw new WixException(WixErrors.ExpectedPatchIdInWixMsp());
            }
            if (null == clientPatchId)
            {
                throw new WixException(WixErrors.ExpectedClientPatchIdInWixMsp());
            }

            // enumerate patch.Media to map diskId to Media row
            Table patchMediaTable = patch.Tables["Media"];

            if (null == patchMediaTable || patchMediaTable.Rows.Count == 0)
            {
                throw new WixException(WixErrors.ExpectedMediaRowsInWixMsp());
            }

            Hashtable mediaRows = new Hashtable(patchMediaTable.Rows.Count);
            foreach (MediaRow row in patchMediaTable.Rows)
            {
                int media = row.DiskId;
                mediaRows[media] = row;
            }

            // enumerate patch.WixPatchBaseline to map baseline to diskId
            Table patchBaselineTable = patch.Tables["WixPatchBaseline"];

            int numPatchBaselineRows = (null != patchBaselineTable) ? patchBaselineTable.Rows.Count : 0;

            Hashtable baselineMedia = new Hashtable(numPatchBaselineRows);
            if (patchBaselineTable != null)
            {
                foreach (Row row in patchBaselineTable.Rows)
                {
                    string baseline = (string)row[0];
                    int media = (int)row[1];
                    int validationFlags = (int)row[2];
                    if (baselineMedia.Contains(baseline))
                    {
                        this.OnMessage(WixErrors.SamePatchBaselineId(row.SourceLineNumbers, baseline));
                    }
                    baselineMedia[baseline] = new int[] { media, validationFlags };
                }
            }

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

            // Remove properties that will be calculated or are reserved.
            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:
                    case SummaryInformation.Patch.Reserved11:
                    case SummaryInformation.Patch.Reserved14:
                    case SummaryInformation.Patch.Reserved16:
                        patchSummaryInfo.Rows.RemoveAt(i);
                        break;
                }
            }

            // Index remaining summary properties.
            SummaryInfoRowCollection summaryInfo = new SummaryInfoRowCollection(patchSummaryInfo);

            // PID_CODEPAGE
            if (!summaryInfo.Contains((int)SummaryInformation.Patch.CodePage))
            {
                // set the code page by default to the same code page for the
                // string pool in the database.
                Row codePage = patchSummaryInfo.CreateRow(null);
                codePage[0] = (int)SummaryInformation.Patch.CodePage;
                codePage[1] = this.patch.Codepage.ToString(CultureInfo.InvariantCulture);
            }

            // 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(CultureInfo.InvariantCulture);

            if (!summaryInfo.Contains((int)SummaryInformation.Patch.Security))
            {
                Row security = patchSummaryInfo.CreateRow(null);
                security[0] = (int)SummaryInformation.Patch.Security;
                security[1] = "4"; // Read-only enforced
            }

            // use authored comments or default to DisplayName (required)
            string comments = null;

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

                if (!summaryInfo.Contains((int)SummaryInformation.Patch.Title) && metadataTable.Contains("DisplayName"))
                {
                    string displayName = (string)metadataTable["DisplayName"];

                    Row title = patchSummaryInfo.CreateRow(null);
                    title[0] = (int)SummaryInformation.Patch.Title;
                    title[1] = displayName;

                    // default comments use DisplayName as-is (no loc)
                    comments = displayName;
                }

                if (!summaryInfo.Contains((int)SummaryInformation.Patch.CodePage) && metadataTable.Contains("CodePage"))
                {
                    Row codePage = patchSummaryInfo.CreateRow(null);
                    codePage[0] = (int)SummaryInformation.Patch.CodePage;
                    codePage[1] = metadataTable["CodePage"];
                }

                if (!summaryInfo.Contains((int)SummaryInformation.Patch.PackageName) && metadataTable.Contains("Description"))
                {
                    Row subject = patchSummaryInfo.CreateRow(null);
                    subject[0] = (int)SummaryInformation.Patch.PackageName;
                    subject[1] = metadataTable["Description"];
                }

                if (!summaryInfo.Contains((int)SummaryInformation.Patch.Manufacturer) && metadataTable.Contains("ManufacturerName"))
                {
                    Row author = patchSummaryInfo.CreateRow(null);
                    author[0] = (int)SummaryInformation.Patch.Manufacturer;
                    author[1] = metadataTable["ManufacturerName"];
                }
            }

            // special metadata marshalled through the build
            Table wixPatchMetadataTable = patch.Tables["WixPatchMetadata"];
            Hashtable wixMetadataTable = new Hashtable();
            if (null != wixPatchMetadataTable)
            {
                foreach (Row row in wixPatchMetadataTable.Rows)
                {
                    wixMetadataTable.Add(row.Fields[0].Data.ToString(), row.Fields[1].Data.ToString());
                }

                if (wixMetadataTable.Contains("Comments"))
                {
                    comments = (string)wixMetadataTable["Comments"];
                }
            }

            // write the package comments to summary info
            if (!summaryInfo.Contains((int)SummaryInformation.Patch.Comments) && null != comments)
            {
                Row commentsRow = patchSummaryInfo.CreateRow(null);
                commentsRow[0] = (int)SummaryInformation.Patch.Comments;
                commentsRow[1] = comments;
            }

            // enumerate transforms
            Dictionary<string, object> productCodes = new Dictionary<string, object>();
            ArrayList transformNames = new ArrayList();
            ArrayList validTransform = new ArrayList();
            int transformCount = 0;
            foreach (PatchTransform mainTransform in transforms)
            {
                string baseline = null;
                int media = -1;
                int validationFlags = 0;

                if (baselineMedia.Contains(mainTransform.Baseline))
                {
                    int[] baselineData = (int[])baselineMedia[mainTransform.Baseline];
                    int newMedia = baselineData[0];
                    if (media != -1 && media != newMedia)
                    {
                        throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, WixStrings.EXP_TransformAuthoredIntoMultipleMedia, media, newMedia));
                    }
                    baseline = mainTransform.Baseline;
                    media = newMedia;
                    validationFlags = baselineData[1];
                }

                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 (!Patch.ReduceTransform(mainTransform.Transform, patchRefTable))
                    {
                        // transform has none of the content authored into this patch
                        continue;
                    }
                }

                // Validate the transform doesn't break any patch specific rules.
                mainTransform.Validate();

                // ensure consistent File.Sequence within each Media
                MediaRow mediaRow = (MediaRow)mediaRows[media];

                // Ensure that files are sequenced after the last file in any transform.
                Table transformMediaTable = mainTransform.Transform.Tables["Media"];
                if (null != transformMediaTable && 0 < transformMediaTable.Rows.Count)
                {
                    foreach (MediaRow transformMediaRow in transformMediaTable.Rows)
                    {
                        if (mediaRow.LastSequence < transformMediaRow.LastSequence)
                        {
                            // The Binder will pre-increment the sequence.
                            mediaRow.LastSequence = transformMediaRow.LastSequence;
                        }
                    }
                }
                
                // Use the Media/@DiskId if greater for backward compatibility.
                if (mediaRow.LastSequence < mediaRow.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;
                Output pairedTransform = this.BuildPairedTransform(patchId, clientPatchId, mainTransform.Transform, mediaRow, validationFlags, out productCode);
                productCodes[productCode] = null;
                DictionaryEntry entry = new DictionaryEntry();
                entry.Key = productCode;
                entry.Value = mainTransform.Transform;
                validTransform.Add(entry);

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

            if (!attachedTransform)
            {
                throw new WixException(WixErrors.PatchWithoutValidTransforms());
            }

            // Validate that a patch authored as removable is actually removable
            if (metadataTable.Contains("AllowRemoval"))
            {
                if ("1" == metadataTable["AllowRemoval"].ToString())
                {
                    ArrayList tables = Patch.GetPatchUninstallBreakingTables();
                    bool result = true;
                    foreach (DictionaryEntry entry in validTransform)
                    {
                        result &= this.CheckUninstallableTransform(entry.Key.ToString(), (Output)entry.Value, tables);
                    }

                    if (!result)
                    {
                        throw new WixException(WixErrors.PatchNotRemovable());
                    }
                }
            }

            // Finish filling tables with transform-dependent data.
            // Semicolon delimited list of the product codes that can accept the patch.
            Table wixPatchTargetTable = patch.Tables["WixPatchTarget"];
            if (null != wixPatchTargetTable)
            {
                Dictionary<string, object> targets = new Dictionary<string, object>();
                bool replace = true;
                foreach (Row wixPatchTargetRow in wixPatchTargetTable.Rows)
                {
                    string target = wixPatchTargetRow[0].ToString();
                    if (0 == String.CompareOrdinal("*", target))
                    {
                        replace = false;
                    }
                    else
                    {
                        targets[target] = null;
                    }
                }

                // Replace the target ProductCodes with the authored list.
                if (replace)
                {
                    productCodes = targets;
                }
                else
                {
                    // Copy the authored target ProductCodes into the list.
                    foreach (string target in targets.Keys)
                    {
                        productCodes[target] = null;
                    }
                }
            }

            string[] uniqueProductCodes = new string[productCodes.Keys.Count];
            productCodes.Keys.CopyTo(uniqueProductCodes, 0);

            Row templateRow = patchSummaryInfo.CreateRow(null);
            templateRow[0] = (int)SummaryInformation.Patch.ProductCodes;
            templateRow[1] = String.Join(";", uniqueProductCodes);

            // 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)));

            // inspect the patch and filtered transforms
            foreach (InspectorExtension inspectorExtension in this.inspectorExtensions)
            {
                inspectorExtension.Core = inspectorCore;
                inspectorExtension.InspectPatch(this.patch);

                // reset
                inspectorExtension.Core = null;
            }
        }
Exemplo n.º 2
0
        public Intermediate Compile(XmlDocument source)
        {
            if (null == source)
            {
                throw new ArgumentNullException("source");
            }

            bool encounteredError = false;

            // create the intermediate
            Intermediate target = new Intermediate();

            // try to compile it
            try
            {
                this.core = new CompilerCore(target, this.tableDefinitions, this.extensions, this.Message, this.schema);
                this.core.ShowPedanticMessages = this.showPedanticMessages;
                this.core.CurrentPlatform = this.currentPlatform;
                this.core.FipsCompliant = this.fipsCompliant;

                foreach (CompilerExtension extension in this.extensions.Values)
                {
                    extension.Core = this.core;
                    extension.InitializeCompile();
                }

                // parse the document
                SourceLineNumberCollection sourceLineNumbers = Preprocessor.GetSourceLineNumbers(source.DocumentElement);
                if ("Wix" == source.DocumentElement.LocalName)
                {
                    if (this.schema.TargetNamespace == source.DocumentElement.NamespaceURI)
                    {
                        this.ParseWixElement(source.DocumentElement);
                    }
                    else // invalid or missing namespace
                    {
                        if (0 == source.DocumentElement.NamespaceURI.Length)
                        {
                            this.core.OnMessage(WixErrors.InvalidWixXmlNamespace(sourceLineNumbers, "Wix", this.schema.TargetNamespace));
                        }
                        else
                        {
                            this.core.OnMessage(WixErrors.InvalidWixXmlNamespace(sourceLineNumbers, "Wix", source.DocumentElement.NamespaceURI, this.schema.TargetNamespace));
                        }
                    }
                }
                else
                {
                    this.core.OnMessage(WixErrors.InvalidDocumentElement(sourceLineNumbers, source.DocumentElement.Name, "source", "Wix"));
                }

                // perform schema validation if there were no errors and validation isn't suppressed
                if (!this.core.EncounteredError && !this.suppressValidation)
                {
                    this.ValidateDocument(source);
                }

                // inspect the document
                InspectorCore inspectorCore = new InspectorCore(this.Message);
                foreach (InspectorExtension inspectorExtension in this.inspectorExtensions)
                {
                    inspectorExtension.Core = inspectorCore;
                    inspectorExtension.InspectIntermediate(target);

                    // reset
                    inspectorExtension.Core = null;
                }

                if (inspectorCore.EncounteredError)
                {
                    encounteredError = true;
                }
            }
            finally
            {
                if (this.core.EncounteredError)
                {
                    encounteredError = true;
                }

                foreach (CompilerExtension extension in this.extensions.Values)
                {
                    extension.FinalizeCompile();
                    extension.Core = null;
                }
                this.core = null;
            }

            // return the compiled intermediate only if it completed successfully
            return (encounteredError ? null : target);
        }
Exemplo n.º 3
0
        public XmlDocument Process(string sourceFile, Hashtable variables)
        {
            Stream processed = new MemoryStream();
            XmlDocument sourceDocument = new XmlDocument();

            try
            {
                this.core = new PreprocessorCore(this.extensionsByPrefix, this.Message, sourceFile, variables);
                this.core.ResolvedVariableHandler = this.ResolvedVariable;
                this.core.CurrentPlatform = this.currentPlatform;
                this.currentLineNumberWritten = false;
                this.currentLineNumber = new SourceLineNumber(sourceFile);
                this.currentFileStack.Clear();
                this.currentFileStack.Push(this.core.GetVariableValue(this.GetCurrentSourceLineNumbers(), "sys", "SOURCEFILEDIR"));

                // open the source file for processing
                using (Stream sourceStream = new FileStream(sourceFile, FileMode.Open, FileAccess.Read, FileShare.Read))
                {
                    // inspect the raw source
                    InspectorCore inspectorCore = new InspectorCore(this.Message);
                    foreach (InspectorExtension inspectorExtension in this.inspectorExtensions)
                    {
                        inspectorExtension.Core = inspectorCore;
                        inspectorExtension.InspectSource(sourceStream);

                        // reset
                        inspectorExtension.Core = null;
                        sourceStream.Position = 0;
                    }

                    if (inspectorCore.EncounteredError)
                    {
                        return null;
                    }

                    XmlReader reader = new XmlTextReader(sourceStream);
                    XmlTextWriter writer = new XmlTextWriter(processed, Encoding.UTF8);

                    // process the reader into the writer
                    try
                    {
                        foreach (PreprocessorExtension extension in this.extensions)
                        {
                            extension.Core = this.core;
                            extension.InitializePreprocess();
                        }
                        this.PreprocessReader(false, reader, writer, 0);
                    }
                    catch (XmlException e)
                    {
                        this.UpdateInformation(reader, 0);
                        throw new WixException(WixErrors.InvalidXml(this.GetCurrentSourceLineNumbers(), "source", e.Message));
                    }

                    writer.Flush();
                }

                // fire event with processed stream
                ProcessedStreamEventArgs args = new ProcessedStreamEventArgs(sourceFile, processed);
                this.OnProcessedStream(args);

                // create an XML Document from the post-processed memory stream
                XmlTextReader xmlReader = null;

                try
                {
                    // create an XmlReader with the path to the original file
                    // to properly set the BaseURI property of the XmlDocument
                    processed.Position = 0;
                    xmlReader = new XmlTextReader(new Uri(Path.GetFullPath(sourceFile)).AbsoluteUri, processed);
                    sourceDocument.Load(xmlReader);

                }
                catch (XmlException e)
                {
                    this.UpdateInformation(xmlReader, 0);
                    throw new WixException(WixErrors.InvalidXml(this.GetCurrentSourceLineNumbers(), "source", e.Message));
                }
                finally
                {
                    if (null != xmlReader)
                    {
                        xmlReader.Close();
                    }
                }

                // preprocess the generated XML Document
                foreach (PreprocessorExtension extension in this.extensions)
                {
                    extension.PreprocessDocument(sourceDocument);
                }
            }
            finally
            {
                // finalize the preprocessing
                foreach (PreprocessorExtension extension in this.extensions)
                {
                    extension.FinalizePreprocess();
                    extension.Core = null;
                }
            }

            if (this.core.EncounteredError)
            {
                return null;
            }
            else
            {
                if (null != this.preprocessOut)
                {
                    sourceDocument.Save(this.preprocessOut);
                    this.preprocessOut.Flush();
                }

                return sourceDocument;
            }
        }
Exemplo n.º 4
0
        /// <summary>
        /// Creates a transform by diffing two outputs.
        /// </summary>
        /// <param name="targetOutput">The target output.</param>
        /// <param name="updatedOutput">The updated output.</param>
        /// <param name="validationFlags"></param>
        /// <returns>The transform.</returns>
        public Output Diff(Output targetOutput, Output updatedOutput, TransformFlags validationFlags)
        {
            Output transform = new Output(null);
            transform.Type = OutputType.Transform;
            transform.Codepage = updatedOutput.Codepage;
            this.transformSummaryInfo = new SummaryInformationStreams();

            // compare the codepages
            if (targetOutput.Codepage != updatedOutput.Codepage && 0 == (TransformFlags.ErrorChangeCodePage & validationFlags))
            {
                this.OnMessage(WixErrors.OutputCodepageMismatch(targetOutput.SourceLineNumbers, targetOutput.Codepage, updatedOutput.Codepage));
                if (null != updatedOutput.SourceLineNumbers)
                {
                    this.OnMessage(WixErrors.OutputCodepageMismatch2(updatedOutput.SourceLineNumbers));
                }
            }

            // compare the output types
            if (targetOutput.Type != updatedOutput.Type)
            {
                throw new WixException(WixErrors.OutputTypeMismatch(targetOutput.SourceLineNumbers, targetOutput.Type.ToString(), updatedOutput.Type.ToString()));
            }

            // compare the contents of the tables
            foreach (Table targetTable in targetOutput.Tables)
            {
                Table updatedTable = updatedOutput.Tables[targetTable.Name];
                TableOperation operation = TableOperation.None;

                RowCollection rows = this.CompareTables(targetOutput, targetTable, updatedTable, out operation);

                if (TableOperation.Drop == operation)
                {
                    Table droppedTable = transform.Tables.EnsureTable(null, targetTable.Definition);
                    droppedTable.Operation = TableOperation.Drop;
                }
                else if(TableOperation.None == operation)
                {
                    Table modified = transform.Tables.EnsureTable(null, updatedTable.Definition);
                    modified.Rows.AddRange(rows);
                }
            }

            // added tables
            foreach (Table updatedTable in updatedOutput.Tables)
            {
                if (null == targetOutput.Tables[updatedTable.Name])
                {
                    Table addedTable = transform.Tables.EnsureTable(null, updatedTable.Definition);
                    addedTable.Operation = TableOperation.Add;

                    foreach (Row updatedRow in updatedTable.Rows)
                    {
                        updatedRow.Operation = RowOperation.Add;
                        updatedRow.SectionId = sectionDelimiter + updatedRow.SectionId;
                        addedTable.Rows.Add(updatedRow);
                    }
                }
            }

            // set summary information properties
            if (!this.suppressKeepingSpecialRows)
            {
                Table summaryInfoTable = transform.Tables["_SummaryInformation"];
                this.UpdateTransformSummaryInformationTable(summaryInfoTable, validationFlags);
            }

            // inspect the transform
            InspectorCore inspectorCore = new InspectorCore(this.Message);
            foreach (InspectorExtension inspectorExtension in this.inspectorExtensions)
            {
                inspectorExtension.Core = inspectorCore;
                inspectorExtension.InspectTransform(transform);

                // reset
                inspectorExtension.Core = null;
            }

            return transform;
        }
Exemplo n.º 5
0
Arquivo: Linker.cs Projeto: zooba/wix3
        public Output Link(SectionCollection sections, ArrayList transforms, OutputType expectedOutputType)
        {
            Output output = null;

            try
            {
                SymbolCollection allSymbols;
                Section entrySection;
                bool containsModuleSubstitution = false;
                bool containsModuleConfiguration = false;

                StringCollection referencedSymbols = new StringCollection();
                ArrayList unresolvedReferences = new ArrayList();

                ConnectToFeatureCollection componentsToFeatures = new ConnectToFeatureCollection();
                ConnectToFeatureCollection featuresToFeatures = new ConnectToFeatureCollection();
                ConnectToFeatureCollection modulesToFeatures = new ConnectToFeatureCollection();

                this.activeOutput = null;
                this.encounteredError = false;

                SortedList adminProperties = new SortedList();
                SortedList secureProperties = new SortedList();
                SortedList hiddenProperties = new SortedList();

                RowCollection actionRows = new RowCollection();
                RowCollection suppressActionRows = new RowCollection();

                TableDefinitionCollection customTableDefinitions = new TableDefinitionCollection();
                RowCollection customRows = new RowCollection();

                StringCollection generatedShortFileNameIdentifiers = new StringCollection();
                Hashtable generatedShortFileNames = new Hashtable();

                Hashtable multipleFeatureComponents = new Hashtable();

                Hashtable wixVariables = new Hashtable();

                // verify that modularization types match for foreign key relationships
                foreach (TableDefinition tableDefinition in this.tableDefinitions)
                {
                    foreach (ColumnDefinition columnDefinition in tableDefinition.Columns)
                    {
                        if (null != columnDefinition.KeyTable && 0 > columnDefinition.KeyTable.IndexOf(';') && columnDefinition.IsKeyColumnSet)
                        {
                            try
                            {
                                TableDefinition keyTableDefinition = this.tableDefinitions[columnDefinition.KeyTable];

                                if (0 >= columnDefinition.KeyColumn || keyTableDefinition.Columns.Count < columnDefinition.KeyColumn)
                                {
                                    this.OnMessage(WixErrors.InvalidKeyColumn(tableDefinition.Name, columnDefinition.Name, columnDefinition.KeyTable, columnDefinition.KeyColumn));
                                }
                                else if (keyTableDefinition.Columns[columnDefinition.KeyColumn - 1].ModularizeType != columnDefinition.ModularizeType && ColumnModularizeType.CompanionFile != columnDefinition.ModularizeType)
                                {
                                    this.OnMessage(WixErrors.CollidingModularizationTypes(tableDefinition.Name, columnDefinition.Name, columnDefinition.KeyTable, columnDefinition.KeyColumn, columnDefinition.ModularizeType.ToString(), keyTableDefinition.Columns[columnDefinition.KeyColumn - 1].ModularizeType.ToString()));
                                }
                            }
                            catch (WixMissingTableDefinitionException)
                            {
                                // ignore missing table definitions - this error is caught in other places
                            }
                        }
                    }
                }

                // add in the extension sections
                foreach (WixExtension extension in this.extensions)
                {
                    Library library = extension.GetLibrary(this.tableDefinitions);

                    if (null != library)
                    {
                        sections.AddRange(library.Sections);
                    }
                }

                // first find the entry section and create the symbols hash for all the sections
                sections.FindEntrySectionAndLoadSymbols(this.allowIdenticalRows, this, expectedOutputType, out entrySection, out allSymbols);

                // should have found an entry section by now
                if (null == entrySection)
                {
                    throw new WixException(WixErrors.MissingEntrySection(expectedOutputType.ToString()));
                }

                // add the missing standard action symbols
                this.LoadStandardActionSymbols(allSymbols);

                // now that we know where we're starting from, create the output object
                output = new Output(null);
                output.EntrySection = entrySection; // Note: this entry section will get added to the Output.Sections collection later
                if (null != this.localizer && -1 != this.localizer.Codepage)
                {
                    output.Codepage = this.localizer.Codepage;
                }
                this.activeOutput = output;

                // Resolve the symbol references to find the set of sections we
                // care about for linking.  Of course, we start with the entry
                // section (that's how it got its name after all).
                output.Sections.AddRange(output.EntrySection.ResolveReferences(output.Type, allSymbols, referencedSymbols, unresolvedReferences, this));

                // Flattening the complex references that participate in groups.
                this.FlattenSectionsComplexReferences(output.Sections);

                if (this.encounteredError)
                {
                    return null;
                }

                // The hard part in linking is processing the complex references.
                this.ProcessComplexReferences(output, output.Sections, referencedSymbols, componentsToFeatures, featuresToFeatures, modulesToFeatures);
                for (int i = 0; i < unresolvedReferences.Count; ++i)
                {
                    Section.SimpleReferenceSection referenceSection = (Section.SimpleReferenceSection)unresolvedReferences[i];
                    if (this.allowUnresolvedReferences)
                    {
                        this.OnMessage(WixWarnings.UnresolvedReferenceWarning(referenceSection.WixSimpleReferenceRow.SourceLineNumbers, referenceSection.Section.Type.ToString(), referenceSection.Section.Id, referenceSection.WixSimpleReferenceRow.SymbolicName));
                    }
                    else
                    {
                        this.OnMessage(WixErrors.UnresolvedReference(referenceSection.WixSimpleReferenceRow.SourceLineNumbers, referenceSection.Section.Type.ToString(), referenceSection.Section.Id, referenceSection.WixSimpleReferenceRow.SymbolicName));
                    }
                }

                if (this.encounteredError)
                {
                    return null;
                }

                SymbolCollection unreferencedSymbols = output.Sections.GetOrphanedSymbols(referencedSymbols, this);

                // Display a warning message for Components that were never referenced by a Feature.
                foreach (Symbol symbol in unreferencedSymbols)
                {
                    if ("Component" == symbol.Row.Table.Name)
                    {
                        this.OnMessage(WixErrors.OrphanedComponent(symbol.Row.SourceLineNumbers, (string)symbol.Row[0]));
                    }
                }

                Dictionary<string, List<Symbol>> duplicatedSymbols = output.Sections.GetDuplicateSymbols(this);

                // Display a warning message for Components that were never referenced by a Feature.
                foreach (List<Symbol> duplicatedSymbolList in duplicatedSymbols.Values)
                {
                    Symbol symbol = duplicatedSymbolList[0];

                    // Certain tables allow duplicates because they allow overrides.
                    if (symbol.Row.Table.Name != "WixAction" &&
                        symbol.Row.Table.Name != "WixVariable")
                    {
                        this.OnMessage(WixErrors.DuplicateSymbol(symbol.Row.SourceLineNumbers, symbol.Name));

                        for (int i = 1; i < duplicatedSymbolList.Count; i++)
                        {
                            Symbol duplicateSymbol = duplicatedSymbolList[i];
                            this.OnMessage(WixErrors.DuplicateSymbol2(duplicateSymbol.Row.SourceLineNumbers));
                        }
                    }
                }

                if (this.encounteredError)
                {
                    return null;
                }

                if (null != this.unreferencedSymbolsFile)
                {
                    sections.GetOrphanedSymbols(referencedSymbols, this).OutputSymbols(this.unreferencedSymbolsFile);
                }

                // resolve the feature to feature connects
                this.ResolveFeatureToFeatureConnects(featuresToFeatures, allSymbols);

                // start generating OutputTables and OutputRows for all the sections in the output
                RowCollection ensureTableRows = new RowCollection();
                int sectionCount = 0;
                foreach (Section section in output.Sections)
                {
                    sectionCount++;
                    string sectionId = section.Id;
                    if (null == sectionId && this.sectionIdOnRows)
                    {
                        sectionId = "wix.section." + sectionCount.ToString(CultureInfo.InvariantCulture);
                    }

                    foreach (Table table in section.Tables)
                    {
                        // By default, copy rows unless we've been asked to drop unreal tables from
                        // the output and it's an unreal table and *not* a UX Manifest table.
                        bool copyRows = true;
                        if (this.dropUnrealTables && table.Definition.IsUnreal && !table.Definition.IsBootstrapperApplicationData)
                        {
                            copyRows = false;
                        }

                        // handle special tables
                        switch (table.Name)
                        {
                            case "AppSearch":
                                this.activeOutput.EnsureTable(this.tableDefinitions["Signature"]);
                                break;

                            case "Class":
                                if (OutputType.Product == output.Type)
                                {
                                    this.ResolveFeatures(table.Rows, 2, 11, componentsToFeatures, multipleFeatureComponents);
                                }
                                break;

                            case "ChainPackage":
                            case "ChainPackageGroup":
                            case "MsiProperty":
                                copyRows = true;
                                break;

                            case "CustomAction":
                                if (OutputType.Module == this.activeOutput.Type)
                                {
                                    this.activeOutput.EnsureTable(this.tableDefinitions["AdminExecuteSequence"]);
                                    this.activeOutput.EnsureTable(this.tableDefinitions["AdminUISequence"]);
                                    this.activeOutput.EnsureTable(this.tableDefinitions["AdvtExecuteSequence"]);
                                    this.activeOutput.EnsureTable(this.tableDefinitions["InstallExecuteSequence"]);
                                    this.activeOutput.EnsureTable(this.tableDefinitions["InstallUISequence"]);
                                }

                                foreach (Row row in table.Rows)
                                {
                                    // For script CAs that specify HideTarget we should also hide the CA data property for the action.
                                    int bits = Convert.ToInt32(row[1]);
                                    if (MsiInterop.MsidbCustomActionTypeHideTarget == (bits & MsiInterop.MsidbCustomActionTypeHideTarget) &&
                                        MsiInterop.MsidbCustomActionTypeInScript == (bits & MsiInterop.MsidbCustomActionTypeInScript))
                                    {
                                        hiddenProperties[Convert.ToString(row[0])] = null;
                                    }
                                }
                                break;

                            case "Dialog":
                                this.activeOutput.EnsureTable(this.tableDefinitions["ListBox"]);
                                break;

                            case "Directory":
                                foreach (Row row in table.Rows)
                                {
                                    if (OutputType.Module == this.activeOutput.Type)
                                    {
                                        string directory = row[0].ToString();
                                        if (Util.IsStandardDirectory(directory))
                                        {
                                            // if the directory table contains references to standard windows folders
                                            // mergemod.dll will add customactions to set the MSM directory to
                                            // the same directory as the standard windows folder and will add references to
                                            // custom action to all the standard sequence tables.  A problem will occur
                                            // if the MSI does not have these tables as mergemod.dll does not add these
                                            // tables to the MSI if absent.  This code adds the tables in case mergemod.dll
                                            // needs them.
                                            this.activeOutput.EnsureTable(this.tableDefinitions["CustomAction"]);
                                            this.activeOutput.EnsureTable(this.tableDefinitions["AdminExecuteSequence"]);
                                            this.activeOutput.EnsureTable(this.tableDefinitions["AdminUISequence"]);
                                            this.activeOutput.EnsureTable(this.tableDefinitions["AdvtExecuteSequence"]);
                                            this.activeOutput.EnsureTable(this.tableDefinitions["InstallExecuteSequence"]);
                                            this.activeOutput.EnsureTable(this.tableDefinitions["InstallUISequence"]);
                                        }
                                        else
                                        {
                                            foreach (string standardDirectory in Util.StandardDirectories.Keys)
                                            {
                                                if (directory.StartsWith(standardDirectory, StringComparison.Ordinal))
                                                {
                                                    this.OnMessage(WixWarnings.StandardDirectoryConflictInMergeModule(row.SourceLineNumbers, directory, standardDirectory));
                                                }
                                            }
                                        }
                                    }
                                }
                                break;

                            case "Extension":
                                if (OutputType.Product == output.Type)
                                {
                                    this.ResolveFeatures(table.Rows, 1, 4, componentsToFeatures, multipleFeatureComponents);
                                }
                                break;

                            case "ModuleSubstitution":
                                containsModuleSubstitution = true;
                                break;

                            case "ModuleConfiguration":
                                containsModuleConfiguration = true;
                                break;

                            case "MsiAssembly":
                                if (this.suppressMsiAssemblyTable)
                                {
                                    copyRows = false;
                                }
                                else if (OutputType.Product == output.Type)
                                {
                                    this.ResolveFeatures(table.Rows, 0, 1, componentsToFeatures, multipleFeatureComponents);
                                }
                                break;

                            case "ProgId":
                                // the Extension table is required with a ProgId table
                                this.activeOutput.EnsureTable(this.tableDefinitions["Extension"]);
                                break;

                            case "Property":
                                for (int i = 0; i < table.Rows.Count; i++)
                                {
                                    if (null == table.Rows[i][1])
                                    {
                                        table.Rows.RemoveAt(i);
                                        i--;
                                    }
                                }
                                break;

                            case "PublishComponent":
                                if (OutputType.Product == output.Type)
                                {
                                    this.ResolveFeatures(table.Rows, 2, 4, componentsToFeatures, multipleFeatureComponents);
                                }
                                break;

                            case "Shortcut":
                                if (OutputType.Product == output.Type)
                                {
                                    this.ResolveFeatures(table.Rows, 3, 4, componentsToFeatures, multipleFeatureComponents);
                                }
                                break;

                            case "TypeLib":
                                if (OutputType.Product == output.Type)
                                {
                                    this.ResolveFeatures(table.Rows, 2, 6, componentsToFeatures, multipleFeatureComponents);
                                }
                                break;

                            case "Upgrade":
                                foreach (UpgradeRow row in table.Rows)
                                {
                                    secureProperties[row.ActionProperty] = null;
                                }
                                break;

                            case "Variable":
                                copyRows = true;
                                break;

                            case "WixAction":
                                if (this.sectionIdOnRows)
                                {
                                    foreach (Row row in table.Rows)
                                    {
                                        row.SectionId = sectionId;
                                    }
                                }
                                actionRows.AddRange(table.Rows);
                                break;

                            case "WixBBControl":
                            case "WixControl":
                                copyRows = true;
                                break;

                            case "WixCustomTable":
                                this.LinkCustomTable(table, customTableDefinitions);
                                copyRows = false; // we've created table definitions from these rows, no need to process them any longer
                                break;

                            case "WixCustomRow":
                                foreach (Row row in table.Rows)
                                {
                                    row.SectionId = (this.sectionIdOnRows ? sectionId : null);
                                    customRows.Add(row);
                                }
                                copyRows = false;
                                break;

                            case "WixEnsureTable":
                                ensureTableRows.AddRange(table.Rows);
                                break;

                            case "WixFile":
                                foreach (Row row in table.Rows)
                                {
                                    // DiskId is not valid when creating a module, so set it to
                                    // 0 for all files to ensure proper sorting in the binder
                                    if (OutputType.Module == this.activeOutput.Type)
                                    {
                                        row[5] = 0;
                                    }

                                    // if the short file name was generated, check for collisions
                                    if (0x1 == (int)row[9])
                                    {
                                        generatedShortFileNameIdentifiers.Add((string)row[0]);
                                    }
                                }
                                copyRows = true;
                                break;

                            case "WixFragment":
                                copyRows = true;
                                break;

                            case "WixGroup":
                                copyRows = true;
                                break;

                            case "WixInstanceTransforms":
                                copyRows = true;
                                break;

                            case "WixMedia":
                                copyRows = true;
                                break;

                            case "WixMerge":
                                if (OutputType.Product == output.Type)
                                {
                                    this.ResolveFeatures(table.Rows, 0, 7, modulesToFeatures, null);
                                }
                                copyRows = true;
                                break;

                            case "WixOrdering":
                                copyRows = true;
                                break;

                            case "WixProperty":
                                foreach (WixPropertyRow wixPropertyRow in table.Rows)
                                {
                                    if (wixPropertyRow.Admin)
                                    {
                                        adminProperties[wixPropertyRow.Id] = null;
                                    }

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

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

                            case "WixSuppressAction":
                                suppressActionRows.AddRange(table.Rows);
                                break;

                            case "WixSuppressModularization":
                                // just copy the rows to the output
                                copyRows = true;
                                break;

                            case "WixVariable":
                                // check for colliding values and collect the wix variable rows
                                foreach (WixVariableRow row in table.Rows)
                                {
                                    WixVariableRow collidingRow = (WixVariableRow)wixVariables[row.Id];

                                    if (null == collidingRow || (collidingRow.Overridable && !row.Overridable))
                                    {
                                        wixVariables[row.Id] = row;
                                    }
                                    else if (!row.Overridable || (collidingRow.Overridable && row.Overridable))
                                    {
                                        this.OnMessage(WixErrors.WixVariableCollision(row.SourceLineNumbers, row.Id));
                                    }
                                }
                                copyRows = false;
                                break;
                            case "WixPatchRef":
                            case "WixPatchBaseline":
                            case "WixPatchId":
                                copyRows = true;
                                break;
                        }

                        if (copyRows)
                        {
                            Table outputTable = this.activeOutput.EnsureTable(this.tableDefinitions[table.Name]);
                            this.CopyTableRowsToOutputTable(table, outputTable, sectionId);
                        }
                    }
                }

                // Verify that there were no duplicate fragment Id's.
                Table wixFragmentTable = this.activeOutput.Tables["WixFragment"];
                Hashtable fragmentIdIndex = new Hashtable();
                if (null != wixFragmentTable)
                {
                    foreach (Row row in wixFragmentTable.Rows)
                    {
                        string fragmentId = row.Fields[0].Data.ToString();
                        if (!fragmentIdIndex.ContainsKey(fragmentId))
                        {
                            fragmentIdIndex.Add(fragmentId, row.SourceLineNumbers);
                        }
                        else
                        {
                            this.OnMessage(WixErrors.DuplicateSymbol(row.SourceLineNumbers, fragmentId));
                            if (null != fragmentIdIndex[fragmentId])
                            {
                                this.OnMessage(WixErrors.DuplicateSymbol2((SourceLineNumberCollection)fragmentIdIndex[fragmentId]));
                            }
                        }
                    }
                }

                // copy the module to feature connections into the output
                if (0 < modulesToFeatures.Count)
                {
                    Table wixFeatureModulesTable = this.activeOutput.EnsureTable(this.tableDefinitions["WixFeatureModules"]);

                    foreach (ConnectToFeature connectToFeature in modulesToFeatures)
                    {
                        foreach (string feature in connectToFeature.ConnectFeatures)
                        {
                            Row row = wixFeatureModulesTable.CreateRow(null);
                            row[0] = feature;
                            row[1] = connectToFeature.ChildId;
                        }
                    }
                }

                // ensure the creation of tables that need to exist
                if (0 < ensureTableRows.Count)
                {
                    foreach (Row row in ensureTableRows)
                    {
                        string tableId = (string)row[0];
                        TableDefinition tableDef = null;

                        try
                        {
                            tableDef = this.tableDefinitions[tableId];
                        }
                        catch (WixMissingTableDefinitionException)
                        {
                            tableDef = customTableDefinitions[tableId];
                        }

                        this.activeOutput.EnsureTable(tableDef);
                    }
                }

                // copy all the suppress action rows to the output to suppress actions from merge modules
                if (0 < suppressActionRows.Count)
                {
                    Table suppressActionTable = this.activeOutput.EnsureTable(this.tableDefinitions["WixSuppressAction"]);
                    suppressActionTable.Rows.AddRange(suppressActionRows);
                }

                // sequence all the actions
                this.SequenceActions(actionRows, suppressActionRows);

                // check for missing table and add them or display an error as appropriate
                switch (this.activeOutput.Type)
                {
                    case OutputType.Module:
                        this.activeOutput.EnsureTable(this.tableDefinitions["Component"]);
                        this.activeOutput.EnsureTable(this.tableDefinitions["Directory"]);
                        this.activeOutput.EnsureTable(this.tableDefinitions["FeatureComponents"]);
                        this.activeOutput.EnsureTable(this.tableDefinitions["File"]);
                        this.activeOutput.EnsureTable(this.tableDefinitions["ModuleComponents"]);
                        this.activeOutput.EnsureTable(this.tableDefinitions["ModuleSignature"]);
                        break;
                    case OutputType.PatchCreation:
                        Table imageFamiliesTable = this.activeOutput.Tables["ImageFamilies"];
                        Table targetImagesTable = this.activeOutput.Tables["TargetImages"];
                        Table upgradedImagesTable = this.activeOutput.Tables["UpgradedImages"];

                        if (null == imageFamiliesTable || 1 > imageFamiliesTable.Rows.Count)
                        {
                            this.OnMessage(WixErrors.ExpectedRowInPatchCreationPackage("ImageFamilies"));
                        }

                        if (null == targetImagesTable || 1 > targetImagesTable.Rows.Count)
                        {
                            this.OnMessage(WixErrors.ExpectedRowInPatchCreationPackage("TargetImages"));
                        }

                        if (null == upgradedImagesTable || 1 > upgradedImagesTable.Rows.Count)
                        {
                            this.OnMessage(WixErrors.ExpectedRowInPatchCreationPackage("UpgradedImages"));
                        }

                        this.activeOutput.EnsureTable(this.tableDefinitions["Properties"]);
                        break;
                    case OutputType.Product:
                        this.activeOutput.EnsureTable(this.tableDefinitions["File"]);
                        this.activeOutput.EnsureTable(this.tableDefinitions["Media"]);
                        break;
                }

                this.CheckForIllegalTables(this.activeOutput);

                // add the custom row data
                foreach (Row row in customRows)
                {
                    TableDefinition customTableDefinition = (TableDefinition)customTableDefinitions[row[0].ToString()];
                    Table customTable = this.activeOutput.EnsureTable(customTableDefinition);
                    Row customRow = customTable.CreateRow(row.SourceLineNumbers);

                    customRow.SectionId = row.SectionId;

                    string[] data = row[1].ToString().Split(Common.CustomRowFieldSeparator);

                    for (int i = 0; i < data.Length; ++i)
                    {
                        bool foundColumn = false;
                        string[] item = data[i].Split(colonCharacter, 2);

                        for (int j = 0; j < customRow.Fields.Length; ++j)
                        {
                            if (customRow.Fields[j].Column.Name == item[0])
                            {
                                if (0 < item[1].Length)
                                {
                                    if (ColumnType.Number == customRow.Fields[j].Column.Type)
                                    {
                                        try
                                        {
                                            customRow.Fields[j].Data = Convert.ToInt32(item[1], CultureInfo.InvariantCulture);
                                        }
                                        catch (FormatException)
                                        {
                                            this.OnMessage(WixErrors.IllegalIntegerValue(row.SourceLineNumbers, customTableDefinition.Columns[i].Name, customTableDefinition.Name, item[1]));
                                        }
                                        catch (OverflowException)
                                        {
                                            this.OnMessage(WixErrors.IllegalIntegerValue(row.SourceLineNumbers, customTableDefinition.Columns[i].Name, customTableDefinition.Name, item[1]));
                                        }
                                    }
                                    else if (ColumnCategory.Identifier == customRow.Fields[j].Column.Category)
                                    {
                                        if (CompilerCore.IsIdentifier(item[1]) || Common.IsValidBinderVariable(item[1]) || ColumnCategory.Formatted == customRow.Fields[j].Column.Category)
                                        {
                                            customRow.Fields[j].Data = item[1];
                                        }
                                        else
                                        {
                                            this.OnMessage(WixErrors.IllegalIdentifier(row.SourceLineNumbers, "Data", item[1]));
                                        }
                                    }
                                    else
                                    {
                                        customRow.Fields[j].Data = item[1];
                                    }
                                }
                                foundColumn = true;
                                break;
                            }
                        }

                        if (!foundColumn)
                        {
                            this.OnMessage(WixErrors.UnexpectedCustomTableColumn(row.SourceLineNumbers, item[0]));
                        }
                    }

                    for (int i = 0; i < customTableDefinition.Columns.Count; ++i)
                    {
                        if (!customTableDefinition.Columns[i].IsNullable && (null == customRow.Fields[i].Data || 0 == customRow.Fields[i].Data.ToString().Length))
                        {
                            this.OnMessage(WixErrors.NoDataForColumn(row.SourceLineNumbers, customTableDefinition.Columns[i].Name, customTableDefinition.Name));
                        }
                    }
                }

                //correct the section Id in FeatureComponents table
                if (this.sectionIdOnRows)
                {
                    Hashtable componentSectionIds = new Hashtable();
                    Table componentTable = output.Tables["Component"];

                    if (null != componentTable)
                    {
                        foreach (Row componentRow in componentTable.Rows)
                        {
                            componentSectionIds.Add(componentRow.Fields[0].Data.ToString(), componentRow.SectionId);
                        }
                    }

                    Table featureComponentsTable = output.Tables["FeatureComponents"];

                    if (null != featureComponentsTable)
                    {
                        foreach (Row featureComponentsRow in featureComponentsTable.Rows)
                        {
                            if (componentSectionIds.Contains(featureComponentsRow.Fields[1].Data.ToString()))
                            {
                                featureComponentsRow.SectionId = (string)componentSectionIds[featureComponentsRow.Fields[1].Data.ToString()];
                            }
                        }
                    }
                }

                // update the special properties
                if (0 < adminProperties.Count)
                {
                    Table propertyTable = this.activeOutput.EnsureTable(this.tableDefinitions["Property"]);

                    Row row = propertyTable.CreateRow(null);
                    row[0] = "AdminProperties";
                    row[1] = GetPropertyListString(adminProperties);
                }

                if (0 < secureProperties.Count)
                {
                    Table propertyTable = this.activeOutput.EnsureTable(this.tableDefinitions["Property"]);

                    Row row = propertyTable.CreateRow(null);
                    row[0] = "SecureCustomProperties";
                    row[1] = GetPropertyListString(secureProperties);
                }

                if (0 < hiddenProperties.Count)
                {
                    Table propertyTable = this.activeOutput.EnsureTable(this.tableDefinitions["Property"]);

                    Row row = propertyTable.CreateRow(null);
                    row[0] = "MsiHiddenProperties";
                    row[1] = GetPropertyListString(hiddenProperties);
                }

                // add the ModuleSubstitution table to the ModuleIgnoreTable
                if (containsModuleSubstitution)
                {
                    Table moduleIgnoreTableTable = this.activeOutput.EnsureTable(this.tableDefinitions["ModuleIgnoreTable"]);

                    Row moduleIgnoreTableRow = moduleIgnoreTableTable.CreateRow(null);
                    moduleIgnoreTableRow[0] = "ModuleSubstitution";
                }

                // add the ModuleConfiguration table to the ModuleIgnoreTable
                if (containsModuleConfiguration)
                {
                    Table moduleIgnoreTableTable = this.activeOutput.EnsureTable(this.tableDefinitions["ModuleIgnoreTable"]);

                    Row moduleIgnoreTableRow = moduleIgnoreTableTable.CreateRow(null);
                    moduleIgnoreTableRow[0] = "ModuleConfiguration";
                }

                // index all the file rows
                FileRowCollection indexedFileRows = new FileRowCollection();
                Table fileTable = this.activeOutput.Tables["File"];
                if (null != fileTable)
                {
                    indexedFileRows.AddRange(fileTable.Rows);
                }

                // flag all the generated short file name collisions
                foreach (string fileId in generatedShortFileNameIdentifiers)
                {
                    FileRow fileRow = indexedFileRows[fileId];

                    string[] names = fileRow.FileName.Split('|');
                    string shortFileName = names[0];

                    // create lists of conflicting generated short file names
                    if (!generatedShortFileNames.Contains(shortFileName))
                    {
                        generatedShortFileNames.Add(shortFileName, new ArrayList());
                    }
                    ((ArrayList)generatedShortFileNames[shortFileName]).Add(fileRow);
                }

                // check for generated short file name collisions
                foreach (DictionaryEntry entry in generatedShortFileNames)
                {
                    string shortFileName = (string)entry.Key;
                    ArrayList fileRows = (ArrayList)entry.Value;

                    if (1 < fileRows.Count)
                    {
                        // sort the rows by DiskId
                        fileRows.Sort();

                        this.OnMessage(WixWarnings.GeneratedShortFileNameConflict(((FileRow)fileRows[0]).SourceLineNumbers, shortFileName));

                        for (int i = 1; i < fileRows.Count; i++)
                        {
                            FileRow fileRow = (FileRow)fileRows[i];

                            if (null != fileRow.SourceLineNumbers)
                            {
                                this.OnMessage(WixWarnings.GeneratedShortFileNameConflict2(fileRow.SourceLineNumbers));
                            }
                        }
                    }
                }

                // copy the wix variable rows to the output after all overriding has been accounted for.
                if (0 < wixVariables.Count)
                {
                    Table wixVariableTable = output.EnsureTable(this.tableDefinitions["WixVariable"]);

                    foreach (WixVariableRow row in wixVariables.Values)
                    {
                        wixVariableTable.Rows.Add(row);
                    }
                }

                // Bundles have groups of data that must be flattened in a way different from other types.
                this.FlattenBundleTables(output);

                if (this.encounteredError)
                {
                    return null;
                }

                this.CheckOutputConsistency(output);

                // inspect the output
                InspectorCore inspectorCore = new InspectorCore(this.Message);
                foreach (InspectorExtension inspectorExtension in this.inspectorExtensions)
                {
                    inspectorExtension.Core = inspectorCore;
                    inspectorExtension.InspectOutput(output);

                    // reset
                    inspectorExtension.Core = null;
                }

                if (inspectorCore.EncounteredError)
                {
                    this.encounteredError = true;
                }
            }
            finally
            {
                this.activeOutput = null;
            }

            return (this.encounteredError ? null : output);
        }
Exemplo n.º 6
0
Arquivo: Binder.cs Projeto: zooba/wix3
        private bool BindDatabase(Output output, string databaseFile)
        {
            foreach (BinderExtension extension in this.extensions)
            {
                extension.DatabaseInitialize(output);
            }

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

            this.WriteBuildInfoTable(output, databaseFile);

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

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

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

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

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

            this.LocalizeUI(output.Tables);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            this.ValidateComponentGuids(output);

            this.UpdateControlText(output);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

                // reset
                inspectorExtension.Core = null;
            }

            if (inspectorCore.EncounteredError)
            {
                return false;
            }

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

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

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

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

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

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

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

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

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

            return !this.core.EncounteredError;
        }
Exemplo n.º 7
0
        /// <summary>
        /// Creates a transform by diffing two outputs.
        /// </summary>
        /// <param name="targetOutput">The target output.</param>
        /// <param name="updatedOutput">The updated output.</param>
        /// <param name="validationFlags"></param>
        /// <returns>The transform.</returns>
        public Output Diff(Output targetOutput, Output updatedOutput, TransformFlags validationFlags)
        {
            Output transform = new Output(null);

            transform.Type            = OutputType.Transform;
            transform.Codepage        = updatedOutput.Codepage;
            this.transformSummaryInfo = new SummaryInformationStreams();

            // compare the codepages
            if (targetOutput.Codepage != updatedOutput.Codepage && 0 == (TransformFlags.ErrorChangeCodePage & validationFlags))
            {
                this.OnMessage(WixErrors.OutputCodepageMismatch(targetOutput.SourceLineNumbers, targetOutput.Codepage, updatedOutput.Codepage));
                if (null != updatedOutput.SourceLineNumbers)
                {
                    this.OnMessage(WixErrors.OutputCodepageMismatch2(updatedOutput.SourceLineNumbers));
                }
            }

            // compare the output types
            if (targetOutput.Type != updatedOutput.Type)
            {
                throw new WixException(WixErrors.OutputTypeMismatch(targetOutput.SourceLineNumbers, targetOutput.Type.ToString(), updatedOutput.Type.ToString()));
            }

            // compare the contents of the tables
            foreach (Table targetTable in targetOutput.Tables)
            {
                Table          updatedTable = updatedOutput.Tables[targetTable.Name];
                TableOperation operation    = TableOperation.None;

                RowCollection rows = this.CompareTables(targetOutput, targetTable, updatedTable, out operation);

                if (TableOperation.Drop == operation)
                {
                    Table droppedTable = transform.Tables.EnsureTable(null, targetTable.Definition);
                    droppedTable.Operation = TableOperation.Drop;
                }
                else if (TableOperation.None == operation)
                {
                    Table modified = transform.Tables.EnsureTable(null, updatedTable.Definition);
                    modified.Rows.AddRange(rows);
                }
            }

            // added tables
            foreach (Table updatedTable in updatedOutput.Tables)
            {
                if (null == targetOutput.Tables[updatedTable.Name])
                {
                    Table addedTable = transform.Tables.EnsureTable(null, updatedTable.Definition);
                    addedTable.Operation = TableOperation.Add;

                    foreach (Row updatedRow in updatedTable.Rows)
                    {
                        updatedRow.Operation = RowOperation.Add;
                        updatedRow.SectionId = sectionDelimiter + updatedRow.SectionId;
                        addedTable.Rows.Add(updatedRow);
                    }
                }
            }

            // set summary information properties
            if (!this.suppressKeepingSpecialRows)
            {
                Table summaryInfoTable = transform.Tables["_SummaryInformation"];
                this.UpdateTransformSummaryInformationTable(summaryInfoTable, validationFlags);
            }

            // inspect the transform
            InspectorCore inspectorCore = new InspectorCore(this.Message);

            foreach (InspectorExtension inspectorExtension in this.inspectorExtensions)
            {
                inspectorExtension.Core = inspectorCore;
                inspectorExtension.InspectTransform(transform);

                // reset
                inspectorExtension.Core = null;
            }

            return(transform);
        }