/// <summary> /// Creates a new empty output object. /// </summary> /// <param name="sourceLineNumbers">The source line information for the output.</param> internal Output(SourceLineNumberCollection sourceLineNumbers) { this.sections = new SectionCollection(); this.sourceLineNumbers = sourceLineNumbers; this.subStorages = new ArrayList(); this.tables = new TableCollection(); }
/// <summary> /// Adds a SectionCollection to the collection. /// </summary> /// <param name="sections">SectionCollection to add to collection.</param> public void AddRange(SectionCollection sections) { if (0 == this.collection.Count) { this.collection = new Dictionary<Section, object>(sections.Count); } foreach (Section section in sections.collection.Keys) { this.collection.Add(section, null); } }
private static void LoadSections(string inputFile, IDictionary<Section, string> sectionFiles, SectionCollection sections) { var fragments = new List<Section>(); foreach (Section section in sections) { if (SectionType.Fragment == section.Type) { fragments.Add(section); } else { // reject any file that isn't all fragments return; } } foreach (Section section in fragments) { sectionFiles[section] = inputFile; } }
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); }
/// <summary> /// Links a collection of sections into an output. /// </summary> /// <param name="sections">The collection of sections to link together.</param> /// <returns>Output object from the linking.</returns> public Output Link(SectionCollection sections) { return this.Link(sections, null, OutputType.Unknown); }
/// <summary> /// Process the complex references. /// </summary> /// <param name="output">Active output to add sections to.</param> /// <param name="sections">Sections that are referenced during the link process.</param> /// <param name="referencedSymbols">Collection of all symbols referenced during linking.</param> /// <param name="componentsToFeatures">Component to feature complex references.</param> /// <param name="featuresToFeatures">Feature to feature complex references.</param> /// <param name="modulesToFeatures">Module to feature complex references.</param> private void ProcessComplexReferences( Output output, SectionCollection sections, StringCollection referencedSymbols, ConnectToFeatureCollection componentsToFeatures, ConnectToFeatureCollection featuresToFeatures, ConnectToFeatureCollection modulesToFeatures) { Hashtable componentsToModules = new Hashtable(); foreach (Section section in sections) { Table wixComplexReferenceTable = section.Tables["WixComplexReference"]; if (null != wixComplexReferenceTable) { foreach (WixComplexReferenceRow wixComplexReferenceRow in wixComplexReferenceTable.Rows) { ConnectToFeature connection; switch (wixComplexReferenceRow.ParentType) { case ComplexReferenceParentType.Feature: switch (wixComplexReferenceRow.ChildType) { case ComplexReferenceChildType.Component: connection = componentsToFeatures[wixComplexReferenceRow.ChildId]; if (null == connection) { componentsToFeatures.Add(new ConnectToFeature(section, wixComplexReferenceRow.ChildId, wixComplexReferenceRow.ParentId, wixComplexReferenceRow.IsPrimary)); } else if (wixComplexReferenceRow.IsPrimary) { if (connection.IsExplicitPrimaryFeature) { this.OnMessage(WixErrors.MultiplePrimaryReferences(section.SourceLineNumbers, wixComplexReferenceRow.ChildType.ToString(), wixComplexReferenceRow.ChildId, wixComplexReferenceRow.ParentType.ToString(), wixComplexReferenceRow.ParentId, (null != connection.PrimaryFeature ? "Feature" : "Product"), (null != connection.PrimaryFeature ? connection.PrimaryFeature : this.activeOutput.EntrySection.Id))); continue; } else { connection.ConnectFeatures.Add(connection.PrimaryFeature); // move the guessed primary feature to the list of connects connection.PrimaryFeature = wixComplexReferenceRow.ParentId; // set the new primary feature connection.IsExplicitPrimaryFeature = true; // and make sure we remember that we set it so we can fail if we try to set it again } } else { connection.ConnectFeatures.Add(wixComplexReferenceRow.ParentId); } // add a row to the FeatureComponents table Table featureComponentsTable = output.EnsureTable(this.tableDefinitions["FeatureComponents"]); Row row = featureComponentsTable.CreateRow(null); if (this.sectionIdOnRows) { row.SectionId = section.Id; } row[0] = wixComplexReferenceRow.ParentId; row[1] = wixComplexReferenceRow.ChildId; // index the component for finding orphaned records string symbolName = String.Concat("Component:", wixComplexReferenceRow.ChildId); if (!referencedSymbols.Contains(symbolName)) { referencedSymbols.Add(symbolName); } break; case ComplexReferenceChildType.Feature: connection = featuresToFeatures[wixComplexReferenceRow.ChildId]; if (null != connection) { this.OnMessage(WixErrors.MultiplePrimaryReferences(section.SourceLineNumbers, wixComplexReferenceRow.ChildType.ToString(), wixComplexReferenceRow.ChildId, wixComplexReferenceRow.ParentType.ToString(), wixComplexReferenceRow.ParentId, (null != connection.PrimaryFeature ? "Feature" : "Product"), (null != connection.PrimaryFeature ? connection.PrimaryFeature : this.activeOutput.EntrySection.Id))); continue; } featuresToFeatures.Add(new ConnectToFeature(section, wixComplexReferenceRow.ChildId, wixComplexReferenceRow.ParentId, wixComplexReferenceRow.IsPrimary)); break; case ComplexReferenceChildType.Module: connection = modulesToFeatures[wixComplexReferenceRow.ChildId]; if (null == connection) { modulesToFeatures.Add(new ConnectToFeature(section, wixComplexReferenceRow.ChildId, wixComplexReferenceRow.ParentId, wixComplexReferenceRow.IsPrimary)); } else if (wixComplexReferenceRow.IsPrimary) { if (connection.IsExplicitPrimaryFeature) { this.OnMessage(WixErrors.MultiplePrimaryReferences(section.SourceLineNumbers, wixComplexReferenceRow.ChildType.ToString(), wixComplexReferenceRow.ChildId, wixComplexReferenceRow.ParentType.ToString(), wixComplexReferenceRow.ParentId, (null != connection.PrimaryFeature ? "Feature" : "Product"), (null != connection.PrimaryFeature ? connection.PrimaryFeature : this.activeOutput.EntrySection.Id))); continue; } else { connection.ConnectFeatures.Add(connection.PrimaryFeature); // move the guessed primary feature to the list of connects connection.PrimaryFeature = wixComplexReferenceRow.ParentId; // set the new primary feature connection.IsExplicitPrimaryFeature = true; // and make sure we remember that we set it so we can fail if we try to set it again } } else { connection.ConnectFeatures.Add(wixComplexReferenceRow.ParentId); } break; default: throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, WixStrings.EXP_UnexpectedComplexReferenceChildType, Enum.GetName(typeof(ComplexReferenceChildType), wixComplexReferenceRow.ChildType))); } break; case ComplexReferenceParentType.Module: switch (wixComplexReferenceRow.ChildType) { case ComplexReferenceChildType.Component: if (componentsToModules.ContainsKey(wixComplexReferenceRow.ChildId)) { this.OnMessage(WixErrors.ComponentReferencedTwice(section.SourceLineNumbers, wixComplexReferenceRow.ChildId)); continue; } else { componentsToModules.Add(wixComplexReferenceRow.ChildId, wixComplexReferenceRow); // should always be new // add a row to the ModuleComponents table Table moduleComponentsTable = output.EnsureTable(this.tableDefinitions["ModuleComponents"]); Row row = moduleComponentsTable.CreateRow(null); if (this.sectionIdOnRows) { row.SectionId = section.Id; } row[0] = wixComplexReferenceRow.ChildId; row[1] = wixComplexReferenceRow.ParentId; row[2] = wixComplexReferenceRow.ParentLanguage; } // index the component for finding orphaned records string componentSymbolName = String.Concat("Component:", wixComplexReferenceRow.ChildId); if (!referencedSymbols.Contains(componentSymbolName)) { referencedSymbols.Add(componentSymbolName); } break; default: throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, WixStrings.EXP_UnexpectedComplexReferenceChildType, Enum.GetName(typeof(ComplexReferenceChildType), wixComplexReferenceRow.ChildType))); } break; case ComplexReferenceParentType.Patch: switch(wixComplexReferenceRow.ChildType) { case ComplexReferenceChildType.PatchFamily: case ComplexReferenceChildType.PatchFamilyGroup: break; default: throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, WixStrings.EXP_UnexpectedComplexReferenceChildType, Enum.GetName(typeof(ComplexReferenceChildType), wixComplexReferenceRow.ChildType))); } break; case ComplexReferenceParentType.Product: switch (wixComplexReferenceRow.ChildType) { case ComplexReferenceChildType.Feature: connection = featuresToFeatures[wixComplexReferenceRow.ChildId]; if (null != connection) { this.OnMessage(WixErrors.MultiplePrimaryReferences(section.SourceLineNumbers, wixComplexReferenceRow.ChildType.ToString(), wixComplexReferenceRow.ChildId, wixComplexReferenceRow.ParentType.ToString(), wixComplexReferenceRow.ParentId, (null != connection.PrimaryFeature ? "Feature" : "Product"), (null != connection.PrimaryFeature ? connection.PrimaryFeature : this.activeOutput.EntrySection.Id))); continue; } featuresToFeatures.Add(new ConnectToFeature(section, wixComplexReferenceRow.ChildId, null, wixComplexReferenceRow.IsPrimary)); break; default: throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, WixStrings.EXP_UnexpectedComplexReferenceChildType, Enum.GetName(typeof(ComplexReferenceChildType), wixComplexReferenceRow.ChildType))); } break; default: // Note: Groups have been processed before getting here so they are not handled by any case above. throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, WixStrings.EXP_UnexpectedComplexReferenceChildType, Enum.GetName(typeof(ComplexReferenceParentType), wixComplexReferenceRow.ParentType))); } } } } }
/// <summary> /// Flattens all complex references in all sections in the collection. /// </summary> /// <param name="sections">Sections that are referenced during the link process.</param> private void FlattenSectionsComplexReferences(SectionCollection sections) { Hashtable parentGroups = new Hashtable(); Hashtable parentGroupsSections = new Hashtable(); Hashtable parentGroupsNeedingProcessing = new Hashtable(); // DisplaySectionComplexReferences("--- section's complex references before flattening ---", sections); // Step 1: Gather all of the complex references that are going participate // in the flatting process. This means complex references that have "grouping // parents" of Features, Modules, and, of course, Groups. These references // that participate in a "grouping parent" will be removed from their section // now and after processing added back in Step 3 below. foreach (Section section in sections) { Table wixComplexReferenceTable = section.Tables["WixComplexReference"]; if (null != wixComplexReferenceTable) { // Count down because we'll sometimes remove items from the list. for (int i = wixComplexReferenceTable.Rows.Count - 1; i >= 0; --i) { WixComplexReferenceRow wixComplexReferenceRow = (WixComplexReferenceRow)wixComplexReferenceTable.Rows[i]; // Only process the "grouping parents" such as FeatureGroup, ComponentGroup, Feature, // and Module. Non-grouping complex references are simple and // resolved during normal complex reference resolutions. if (ComplexReferenceParentType.FeatureGroup == wixComplexReferenceRow.ParentType || ComplexReferenceParentType.ComponentGroup == wixComplexReferenceRow.ParentType || ComplexReferenceParentType.Feature == wixComplexReferenceRow.ParentType || ComplexReferenceParentType.Module == wixComplexReferenceRow.ParentType || ComplexReferenceParentType.PatchFamilyGroup == wixComplexReferenceRow.ParentType || ComplexReferenceParentType.Product == wixComplexReferenceRow.ParentType) { string parentTypeAndId = CombineTypeAndId(wixComplexReferenceRow.ParentType, wixComplexReferenceRow.ParentId); // Group all complex references with a common parent // together so we can find them quickly while processing in // Step 2. ArrayList childrenComplexRefs = parentGroups[parentTypeAndId] as ArrayList; if (null == childrenComplexRefs) { childrenComplexRefs = new ArrayList(); parentGroups.Add(parentTypeAndId, childrenComplexRefs); } childrenComplexRefs.Add(wixComplexReferenceRow); wixComplexReferenceTable.Rows.RemoveAt(i); // Remember the mapping from set of complex references with a common // parent to their section. We'll need this to add them back to the // correct section in Step 3. Section parentSection = parentGroupsSections[parentTypeAndId] as Section; if (null == parentSection) { parentGroupsSections.Add(parentTypeAndId, section); } // Debug.Assert(section == (Section)parentGroupsSections[parentTypeAndId]); // If the child of the complex reference is another group, then in Step 2 // we're going to have to process this complex reference again to copy // the child group's references into the parent group. if ((ComplexReferenceChildType.ComponentGroup == wixComplexReferenceRow.ChildType) || (ComplexReferenceChildType.FeatureGroup == wixComplexReferenceRow.ChildType) || (ComplexReferenceChildType.PatchFamilyGroup == wixComplexReferenceRow.ChildType)) { if (!parentGroupsNeedingProcessing.ContainsKey(parentTypeAndId)) { parentGroupsNeedingProcessing.Add(parentTypeAndId, section); } // Debug.Assert(section == (Section)parentGroupsNeedingProcessing[parentTypeAndId]); } } } } } Debug.Assert(parentGroups.Count == parentGroupsSections.Count); Debug.Assert(parentGroupsNeedingProcessing.Count <= parentGroups.Count); // DisplaySectionComplexReferences("\r\n\r\n--- section's complex references middle of flattening ---", sections); // Step 2: Loop through the parent groups that have nested groups removing // them from the hash table as they are processed. At the end of this the // complex references should all be flattened. string[] keys = new string[parentGroupsNeedingProcessing.Keys.Count]; parentGroupsNeedingProcessing.Keys.CopyTo(keys, 0); foreach (string key in keys) { if (parentGroupsNeedingProcessing.Contains(key)) { Stack loopDetector = new Stack(); this.FlattenGroup(key, loopDetector, parentGroups, parentGroupsNeedingProcessing); } else { // the group must have allready been procesed and removed from the hash table } } Debug.Assert(0 == parentGroupsNeedingProcessing.Count); // Step 3: Finally, ensure that all of the groups that were removed // in Step 1 and flattened in Step 2 are added to their appropriate // section. This is where we will toss out the final no-longer-needed // groups. foreach (string parentGroup in parentGroups.Keys) { Section section = (Section)parentGroupsSections[parentGroup]; Table wixComplexReferenceTable = section.Tables["WixComplexReference"]; foreach (WixComplexReferenceRow wixComplexReferenceRow in (ArrayList)parentGroups[parentGroup]) { if ((ComplexReferenceParentType.FeatureGroup != wixComplexReferenceRow.ParentType) && (ComplexReferenceParentType.ComponentGroup != wixComplexReferenceRow.ParentType) && (ComplexReferenceParentType.PatchFamilyGroup != wixComplexReferenceRow.ParentType)) { wixComplexReferenceTable.Rows.Add(wixComplexReferenceRow); } } } // DisplaySectionComplexReferences("\r\n\r\n--- section's complex references after flattening ---", sections); }
/// <summary> /// Adds a SectionCollection to the collection. /// </summary> /// <param name="sections">SectionCollection to add to collection.</param> public void AddRange(SectionCollection sections) { this.collection.AddRange(sections.collection); }
/// <summary> /// Instantiate a new Library. /// </summary> public Library() { this.localizations = new Hashtable(); this.sections = new SectionCollection(); }
/// <summary> /// Resolves all the simple references in a section. /// </summary> /// <param name="outputType">Active output type.</param> /// <param name="sections">Collection to add sections to.</param> /// <param name="section">Section with references to resolve.</param> /// <param name="allSymbols">Collection of all symbols from loaded intermediates.</param> /// <param name="referencedSymbols">Collection of all symbols referenced during linking.</param> /// <param name="unresolvedReferences">Unresolved references.</param> /// <param name="messageHandler">Message handler to report errors through.</param> /// <remarks>Note: recursive function.</remarks> internal static void ResolveReferences( OutputType outputType, SectionCollection sections, Section section, SymbolCollection allSymbols, StringCollection referencedSymbols, ArrayList unresolvedReferences, IMessageHandler messageHandler) { // if we already have this section bail if (sections.Contains(section)) { return; } // add the section to the output and loop through the rest of the references // in a simple depth-first search sections.Add(section); foreach (Reference reference in section.References) { // if we're building into an output, modules ignore all references to the Media table if (OutputType.Module == outputType && "Media" == reference.TableName) { continue; } Symbol symbol = Common.GetSymbolForReference(section, reference, allSymbols, referencedSymbols, unresolvedReferences, messageHandler); if (null != symbol) { Common.ResolveReferences(outputType, sections, symbol.Section, allSymbols, referencedSymbols, unresolvedReferences, messageHandler); } } }
/// <summary> /// Recursive helper function to resolve all references of passed in section. /// </summary> /// <param name="section">Section with references to resolve.</param> /// <param name="outputType">Parent output type that will get the resolved section collection.</param> /// <param name="allSymbols">All symbols that can be used to resolve section's references.</param> /// <param name="sections">Collection to add sections to during processing.</param> /// <param name="referencedSymbols">Collection populated during resolution of all symbols referenced during linking.</param> /// <param name="unresolvedReferences">Collection populated during resolution of all references that are left unresolved.</param> /// <param name="messageHandler">Message handler to report any duplicate symbols that may be tripped across.</param> /// <remarks>Note: recursive function.</remarks> private static void RecursivelyResolveReferences( Section section, OutputType outputType, SymbolCollection allSymbols, SectionCollection sections, StringCollection referencedSymbols, ArrayList unresolvedReferences, IMessageHandler messageHandler) { // if we already have this section bail if (sections.Contains(section)) { return; } // add the passed in section to the collection of sections sections.Add(section); // process all of the references contained in this section using the collection of // symbols provided. Then recursively call this method to process the // located symbol's section. All in all this is a very simple depth-first // search of the references per-section Table wixSimpleReferenceTable = section.Tables["WixSimpleReference"]; if (null != wixSimpleReferenceTable) { foreach (WixSimpleReferenceRow wixSimpleReferenceRow in wixSimpleReferenceTable.Rows) { // If we're building a Merge Module, ignore all references to the Media table // because Merge Modules don't have Media tables. if (OutputType.Module == outputType && "Media" == wixSimpleReferenceRow.TableName) { continue; } if ("WixAction" == wixSimpleReferenceRow.TableName) { Symbol[] symbols = allSymbols.GetSymbolsForSimpleReference(wixSimpleReferenceRow); if (0 == symbols.Length) { if (null != unresolvedReferences) { unresolvedReferences.Add(new SimpleReferenceSection(section, wixSimpleReferenceRow)); } } else { foreach (Symbol symbol in symbols) { if (null != symbol.Section) { // components are indexed in ResolveComplexReferences if (null != referencedSymbols && null != symbol.Row.TableDefinition.Name && "Component" != symbol.Row.TableDefinition.Name && !referencedSymbols.Contains(symbol.Name)) { referencedSymbols.Add(symbol.Name); } RecursivelyResolveReferences(symbol.Section, outputType, allSymbols, sections, referencedSymbols, unresolvedReferences, messageHandler); } } } } else { Symbol symbol = allSymbols.GetSymbolForSimpleReference(wixSimpleReferenceRow, messageHandler); if (null == symbol) { if (null != unresolvedReferences) { unresolvedReferences.Add(new SimpleReferenceSection(section, wixSimpleReferenceRow)); } } else { // components are indexed in ResolveComplexReferences if (null != referencedSymbols && null != symbol.Row.TableDefinition.Name && "Component" != symbol.Row.TableDefinition.Name && !referencedSymbols.Contains(symbol.Name)) { referencedSymbols.Add(symbol.Name); } RecursivelyResolveReferences(symbol.Section, outputType, allSymbols, sections, referencedSymbols, unresolvedReferences, messageHandler); } } } } }
/// <summary> /// Instantiate a new Library. /// </summary> public Library() { this.localizations = new Hashtable(); this.sections = new SectionCollection(); }
/// <summary> /// Recursive helper function to resolve all references of passed in section. /// </summary> /// <param name="section">Section with references to resolve.</param> /// <param name="outputType">Parent output type that will get the resolved section collection.</param> /// <param name="allSymbols">All symbols that can be used to resolve section's references.</param> /// <param name="sections">Collection to add sections to during processing.</param> /// <param name="referencedSymbols">Collection populated during resolution of all symbols referenced during linking.</param> /// <param name="unresolvedReferences">Collection populated during resolution of all references that are left unresolved.</param> /// <param name="messageHandler">Message handler to report any duplicate symbols that may be tripped across.</param> /// <remarks>Note: recursive function.</remarks> private static void RecursivelyResolveReferences( Section section, OutputType outputType, SymbolCollection allSymbols, SectionCollection sections, StringCollection referencedSymbols, ArrayList unresolvedReferences, IMessageHandler messageHandler) { // if we already have this section bail if (sections.Contains(section)) { return; } // add the passed in section to the collection of sections sections.Add(section); // process all of the references contained in this section using the collection of // symbols provided. Then recursively call this method to process the // located symbol's section. All in all this is a very simple depth-first // search of the references per-section Table wixSimpleReferenceTable = section.Tables["WixSimpleReference"]; if (null != wixSimpleReferenceTable) { foreach (WixSimpleReferenceRow wixSimpleReferenceRow in wixSimpleReferenceTable.Rows) { // If we're building a Merge Module, ignore all references to the Media table // because Merge Modules don't have Media tables. if (OutputType.Module == outputType && "Media" == wixSimpleReferenceRow.TableName) { continue; } if ("WixAction" == wixSimpleReferenceRow.TableName) { Symbol[] symbols = allSymbols.GetSymbolsForSimpleReference(wixSimpleReferenceRow); if (0 == symbols.Length) { if (null != unresolvedReferences) { unresolvedReferences.Add(new SimpleReferenceSection(section, wixSimpleReferenceRow)); } } else { foreach (Symbol symbol in symbols) { if (null != symbol.Section) { // components are indexed in ResolveComplexReferences if (null != referencedSymbols && null != symbol.Row.TableDefinition.Name && "Component" != symbol.Row.TableDefinition.Name && !referencedSymbols.Contains(symbol.Name)) { referencedSymbols.Add(symbol.Name); } RecursivelyResolveReferences(symbol.Section, outputType, allSymbols, sections, referencedSymbols, unresolvedReferences, messageHandler); } } } } else { Symbol symbol = allSymbols.GetSymbolForSimpleReference(wixSimpleReferenceRow, messageHandler); if (null == symbol) { if (null != unresolvedReferences) { unresolvedReferences.Add(new SimpleReferenceSection(section, wixSimpleReferenceRow)); } } else { // components are indexed in ResolveComplexReferences if (null != referencedSymbols && null != symbol.Row.TableDefinition.Name && "Component" != symbol.Row.TableDefinition.Name && !referencedSymbols.Contains(symbol.Name)) { referencedSymbols.Add(symbol.Name); } RecursivelyResolveReferences(symbol.Section, outputType, allSymbols, sections, referencedSymbols, unresolvedReferences, messageHandler); } } } } }
/// <summary> /// Resolves all the simple references in a section. /// </summary> /// <param name="outputType">Parent output type that will get the resolved section collection.</param> /// <param name="allSymbols">Collection of all symbols from loaded intermediates.</param> /// <param name="referencedSymbols">Collection populated during resolution of all symbols referenced during linking.</param> /// <param name="unresolvedReferences">Collection populated during resolution of all references that are left unresolved.</param> /// <param name="messageHandler">Message handler to report any duplicate symbols that may be tripped across.</param> /// <returns>The resolved sections.</returns> internal SectionCollection ResolveReferences( OutputType outputType, SymbolCollection allSymbols, StringCollection referencedSymbols, ArrayList unresolvedReferences, IMessageHandler messageHandler) { SectionCollection sections = new SectionCollection(); RecursivelyResolveReferences(this, outputType, allSymbols, sections, referencedSymbols, unresolvedReferences, messageHandler); return sections; }
/// <summary> /// Validate that a library contains one entry section and no duplicate symbols. /// </summary> /// <param name="messageHandler">Message handler for errors.</param> /// <param name="library">Library to validate.</param> private void Validate(IMessageHandler messageHandler, Library library) { Section entrySection; SymbolCollection allSymbols; ArrayList intermediates = new ArrayList(); SectionCollection sections = new SectionCollection(); StringCollection referencedSymbols = new StringCollection(); ArrayList unresolvedReferences = new ArrayList(); intermediates.AddRange(library.Intermediates); Common.FindEntrySectionAndLoadSymbols((Intermediate[])intermediates.ToArray(typeof(Intermediate)), false, this, out entrySection, out allSymbols); foreach (Intermediate intermediate in library.Intermediates) { foreach (Section section in intermediate.Sections) { Common.ResolveReferences(OutputType.Unknown, sections, section, allSymbols, referencedSymbols, unresolvedReferences, this); } } }
/// <summary> /// Create a library by combining several intermediates (objects). /// </summary> /// <param name="sections">The sections to combine into a library.</param> /// <returns>Returns the new library.</returns> public Library Combine(SectionCollection sections) { Library library = new Library(); library.Sections.AddRange(sections); // check for multiple entry sections and duplicate symbols this.Validate(library); return (this.encounteredError ? null : library); }
/// <summary> /// Instantiate a new Intermediate. /// </summary> public Intermediate() { this.sections = new SectionCollection(); }
/// <summary> /// Process the complex references. /// </summary> /// <param name="output">Active output to add sections to.</param> /// <param name="sections">Sections that are referenced during the link process.</param> /// <param name="referencedSymbols">Collection of all symbols referenced during linking.</param> /// <param name="componentsToComponentGroupsComplexReferences">Component to ComponentGroup complex references.</param> /// <param name="componentGroupsToFeatures">ComponentGroups to features complex references.</param> /// <param name="componentGroupsToModules">ComponentGroups to modules complex references.</param> /// <param name="componentsToFeatures">Component to feature complex references.</param> /// <param name="featuresToFeatures">Feature to feature complex references.</param> private void ProcessComplexReferences( Output output, SectionCollection sections, StringCollection referencedSymbols, ComplexReferenceCollection componentsToComponentGroupsComplexReferences, ConnectToFeatureCollection componentGroupsToFeatures, ConnectToModuleCollection componentGroupsToModules, ConnectToFeatureCollection componentsToFeatures, ConnectToFeatureCollection featuresToFeatures) { Hashtable componentsToModules = new Hashtable(); foreach (Section section in sections) { foreach (ComplexReference cref in section.ComplexReferences) { ConnectToFeature connection; switch (cref.ParentType) { case ComplexReferenceParentType.ComponentGroup: switch (cref.ChildType) { case ComplexReferenceChildType.Component: componentsToComponentGroupsComplexReferences.Add(cref); break; default: throw new ApplicationException("Unexpected complex reference child type."); // TODO: come up with a real exception to throw (Unexpected complex reference child type) } break; case ComplexReferenceParentType.Feature: switch (cref.ChildType) { case ComplexReferenceChildType.Component: connection = componentsToFeatures[cref.ChildId]; if (null == connection) { componentsToFeatures.Add(new ConnectToFeature(section, cref.ChildId, cref.ParentId, cref.IsPrimary)); } else if (cref.IsPrimary && connection.IsExplicitPrimaryFeature) { this.OnMessage(WixErrors.MultiplePrimaryReferences(SourceLineNumberCollection.FromFileName(section.Intermediate.Path), cref.ChildType.ToString(), cref.ChildId, cref.ParentId, connection.PrimaryFeature)); continue; } else if (cref.IsPrimary) { connection.ConnectFeatures.Add(connection.PrimaryFeature); // move the guessed primary feature to the list of connects connection.PrimaryFeature = cref.ParentId; // set the new primary feature connection.IsExplicitPrimaryFeature = true; // and make sure we remember that we set it so we can fail if we try to set it again } else { connection.ConnectFeatures.Add(cref.ParentId); } // add a row to the FeatureComponents table Row row = Common.CreateRowInSection(null, section, this.tableDefinitions["FeatureComponents"]); if (this.sectionIdOnTuples) { row.SectionId = section.Id; } row[0] = cref.ParentId; row[1] = cref.ChildId; // index the component for finding orphaned records string symbolName = String.Concat("Component:", cref.ChildId); if (!referencedSymbols.Contains(symbolName)) { referencedSymbols.Add(symbolName); } break; case ComplexReferenceChildType.ComponentGroup: connection = componentGroupsToFeatures[cref.ChildId]; if (null == connection) { componentGroupsToFeatures.Add(new ConnectToFeature(section, cref.ChildId, cref.ParentId, cref.IsPrimary)); } else if (cref.IsPrimary && connection.IsExplicitPrimaryFeature) { this.OnMessage(WixErrors.MultiplePrimaryReferences(SourceLineNumberCollection.FromFileName(section.Intermediate.Path), cref.ChildType.ToString(), cref.ChildId, cref.ParentId, connection.PrimaryFeature)); continue; } else if (cref.IsPrimary) { connection.ConnectFeatures.Add(connection.PrimaryFeature); connection.PrimaryFeature = cref.ParentId; connection.IsExplicitPrimaryFeature = true; } else { connection.ConnectFeatures.Add(cref.ParentId); } break; case ComplexReferenceChildType.Feature: connection = featuresToFeatures[cref.ChildId]; if (null != connection) { this.OnMessage(WixErrors.MultiplePrimaryReferences(SourceLineNumberCollection.FromFileName(section.Intermediate.Path), cref.ChildType.ToString(), cref.ChildId, cref.ParentId, connection.PrimaryFeature)); continue; } featuresToFeatures.Add(new ConnectToFeature(section, cref.ChildId, cref.ParentId, cref.IsPrimary)); break; case ComplexReferenceChildType.Module: connection = output.ModulesToFeatures[cref.ChildId]; if (null == connection) { output.ModulesToFeatures.Add(new ConnectToFeature(section, cref.ChildId, cref.ParentId, cref.IsPrimary)); } else if (cref.IsPrimary && connection.IsExplicitPrimaryFeature) { this.OnMessage(WixErrors.MultiplePrimaryReferences(SourceLineNumberCollection.FromFileName(section.Intermediate.Path), cref.ChildType.ToString(), cref.ChildId, cref.ParentId, connection.PrimaryFeature)); continue; } else if (cref.IsPrimary) { connection.ConnectFeatures.Add(connection.PrimaryFeature); // move the guessed primary feature to the list of connects connection.PrimaryFeature = cref.ParentId; // set the new primary feature connection.IsExplicitPrimaryFeature = true; // and make sure we remember that we set it so we can fail if we try to set it again } else { connection.ConnectFeatures.Add(cref.ParentId); } break; default: throw new ApplicationException("Unexpected complex reference child type"); // TODO: come up with a real exception to throw (Unexpected complex reference child type) } break; case ComplexReferenceParentType.Module: switch (cref.ChildType) { case ComplexReferenceChildType.Component: if (componentsToModules.ContainsKey(cref.ChildId)) { this.OnMessage(WixErrors.ComponentReferencedTwice(SourceLineNumberCollection.FromFileName(section.Intermediate.Path), cref.ChildId)); continue; } else { componentsToModules.Add(cref.ChildId, cref); // should always be new // add a row to the ModuleComponents table Row row = Common.CreateRowInSection(null, section, this.tableDefinitions["ModuleComponents"]); if (this.sectionIdOnTuples) { row.SectionId = section.Id; } row[0] = cref.ChildId; row[1] = cref.ParentId; row[2] = cref.ParentLanguage; } // index the component for finding orphaned records string componentSymbolName = String.Concat("Component:", cref.ChildId); if (!referencedSymbols.Contains(componentSymbolName)) { referencedSymbols.Add(componentSymbolName); } break; case ComplexReferenceChildType.ComponentGroup: ConnectToModule moduleConnection = componentGroupsToModules[cref.ChildId]; if (null == moduleConnection) { componentGroupsToModules.Add(new ConnectToModule(cref.ChildId, cref.ParentId, cref.ParentLanguage)); } break; default: throw new ApplicationException("Unexpected complex reference child type"); // TODO: come up with a real exception to throw (Unexpected complex reference child type) } break; } } } }
/// <summary> /// Creates a new output object with the specified entry section. /// </summary> /// <param name="entrySection">Entry section for the output.</param> internal Output(Section entrySection) : this() { this.entrySection = entrySection; this.sections = new SectionCollection(); this.codepage = entrySection.Codepage; switch (this.entrySection.Type) { case SectionType.Product: this.type = OutputType.Product; this.compressed = false; break; case SectionType.Module: this.type = OutputType.Module; this.compressed = true; break; case SectionType.PatchCreation: this.type = OutputType.PatchCreation; this.compressed = false; break; default: throw new ApplicationException(String.Format("Unexpected entry section type: {0}", this.entrySection.Type)); } }