/// <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> /// Creates a new section as part of an intermediate. /// </summary> /// <param name="id">Identifier for section.</param> /// <param name="type">Type of section.</param> /// <param name="codepage">Codepage for resulting database.</param> public Section(string id, SectionType type, int codepage) { this.id = id; this.type = type; this.codepage = codepage; this.tables = new TableCollection(); }
/// <summary> /// Creates a new section as part of an intermediate. /// </summary> /// <param name="intermediate">Parent intermediate.</param> /// <param name="id">Identifier for section.</param> /// <param name="type">Type of section.</param> /// <param name="codepage">Codepage for resulting database.</param> public Section(Intermediate intermediate, string id, SectionType type, int codepage) { this.intermediate = intermediate; this.id = id; this.type = type; this.codepage = codepage; this.tables = new TableCollection(); this.references = new ReferenceCollection(); this.ignoreModularizations = new IgnoreModularizationCollection(); this.complexReferences = new ComplexReferenceCollection(); this.featureBacklinks = new FeatureBacklinkCollection(); }
/// <summary> /// Finalize decompilation. /// </summary> /// <param name="tables">The collection of all tables.</param> public virtual void FinalizeDecompile(TableCollection tables) { }
/// <summary> /// Checks the InstallExecuteSequence table to determine where RemoveExistingProducts is scheduled and removes it. /// </summary> /// <param name="tables">The collection of all tables.</param> private static Wix.MajorUpgrade.ScheduleType DetermineMajorUpgradeScheduling(TableCollection tables) { int sequenceRemoveExistingProducts = 0; int sequenceInstallValidate = 0; int sequenceInstallInitialize = 0; int sequenceInstallFinalize = 0; int sequenceInstallExecute = 0; int sequenceInstallExecuteAgain = 0; Table installExecuteSequenceTable = tables["InstallExecuteSequence"]; if (null != installExecuteSequenceTable) { int removeExistingProductsRow = -1; for (int i = 0; i < installExecuteSequenceTable.Rows.Count; i++) { Row row = installExecuteSequenceTable.Rows[i]; string action = Convert.ToString(row[0]); int sequence = Convert.ToInt32(row[2]); switch (action) { case "RemoveExistingProducts": sequenceRemoveExistingProducts = sequence; removeExistingProductsRow = i; break; case "InstallValidate": sequenceInstallValidate = sequence; break; case "InstallInitialize": sequenceInstallInitialize = sequence; break; case "InstallExecute": sequenceInstallExecute = sequence; break; case "InstallExecuteAgain": sequenceInstallExecuteAgain = sequence; break; case "InstallFinalize": sequenceInstallFinalize = sequence; break; } } installExecuteSequenceTable.Rows.RemoveAt(removeExistingProductsRow); } if (0 != sequenceInstallValidate && sequenceInstallValidate < sequenceRemoveExistingProducts && sequenceRemoveExistingProducts < sequenceInstallInitialize) { return Wix.MajorUpgrade.ScheduleType.afterInstallValidate; } else if (0 != sequenceInstallInitialize && sequenceInstallInitialize < sequenceRemoveExistingProducts && sequenceRemoveExistingProducts < sequenceInstallExecute) { return Wix.MajorUpgrade.ScheduleType.afterInstallInitialize; } else if (0 != sequenceInstallExecute && sequenceInstallExecute < sequenceRemoveExistingProducts && sequenceRemoveExistingProducts < sequenceInstallExecuteAgain) { return Wix.MajorUpgrade.ScheduleType.afterInstallExecute; } else if (0 != sequenceInstallExecuteAgain && sequenceInstallExecuteAgain < sequenceRemoveExistingProducts && sequenceRemoveExistingProducts < sequenceInstallFinalize) { return Wix.MajorUpgrade.ScheduleType.afterInstallExecuteAgain; } else { return Wix.MajorUpgrade.ScheduleType.afterInstallFinalize; } }
/// <summary> /// Initialize decompilation. /// </summary> /// <param name="tables">The collection of all tables.</param> private void InitializeDecompile(TableCollection tables) { // reset all the state information this.compressed = false; this.patchTargetFiles.Clear(); this.sequenceElements.Clear(); this.shortNames = false; // set the codepage if its not neutral (0) if (0 != this.codepage) { switch (this.outputType) { case OutputType.Module: ((Wix.Module)this.core.RootElement).Codepage = this.codepage.ToString(CultureInfo.InvariantCulture); break; case OutputType.PatchCreation: ((Wix.PatchCreation)this.core.RootElement).Codepage = this.codepage.ToString(CultureInfo.InvariantCulture); break; case OutputType.Product: ((Wix.Product)this.core.RootElement).Codepage = this.codepage.ToString(CultureInfo.InvariantCulture); break; } } // index the rows from the extension libraries Hashtable indexedExtensionTables = new Hashtable(); foreach (WixExtension extension in this.extensions) { // determine if the extension would like its library rows to be removed // if there is no decompiler extension, assume rows should not be removed if (null == extension.DecompilerExtension || !extension.DecompilerExtension.RemoveLibraryRows) { continue; } Library library = extension.GetLibrary(this.tableDefinitions); if (null != library) { foreach (Section section in library.Sections) { foreach (Table table in section.Tables) { foreach (Row row in table.Rows) { string primaryKey; string tableName; // the Actions table needs to be handled specially if ("WixAction" == table.Name) { primaryKey = Convert.ToString(row[1]); if (OutputType.Module == this.outputType) { tableName = String.Concat("Module", Convert.ToString(row[0])); } else { tableName = Convert.ToString(row[0]); } } else { primaryKey = row.GetPrimaryKey(DecompilerCore.PrimaryKeyDelimiter); tableName = table.Name; } if (null != primaryKey) { if (!indexedExtensionTables.Contains(tableName)) { indexedExtensionTables.Add(tableName, new Hashtable()); } Hashtable indexedExtensionRows = (Hashtable)indexedExtensionTables[tableName]; indexedExtensionRows[primaryKey] = null; } } } } } } // remove the rows from the extension libraries (to allow full round-tripping) foreach (string tableName in indexedExtensionTables.Keys) { Table table = tables[tableName]; Hashtable indexedExtensionRows = (Hashtable)indexedExtensionTables[tableName]; if (null != table) { RowCollection originalRows = table.Rows.Clone(); // remove the original rows so that they can be added back if they should remain table.Rows.Clear(); foreach (Row row in originalRows) { if (!indexedExtensionRows.Contains(row.GetPrimaryKey(DecompilerCore.PrimaryKeyDelimiter))) { table.Rows.Add(row); } } } } }
/// <summary> /// Finalize the Upgrade table. /// </summary> /// <param name="tables">The collection of all tables.</param> /// <remarks> /// Decompile the rows from the Upgrade and LaunchCondition tables /// created by the MajorUpgrade element. /// </remarks> private void FinalizeUpgradeTable(TableCollection tables) { Table launchConditionTable = tables["LaunchCondition"]; Table upgradeTable = tables["Upgrade"]; string downgradeErrorMessage = null; string disallowUpgradeErrorMessage = null; Wix.MajorUpgrade majorUpgrade = new Wix.MajorUpgrade(); // find the DowngradePreventedCondition launch condition message if (null != launchConditionTable && 0 < launchConditionTable.Rows.Count) { foreach (Row launchRow in launchConditionTable.Rows) { if (Compiler.DowngradePreventedCondition == Convert.ToString(launchRow[0])) { downgradeErrorMessage = Convert.ToString(launchRow[1]); } else if (Compiler.UpgradePreventedCondition == Convert.ToString(launchRow[0])) { disallowUpgradeErrorMessage = Convert.ToString(launchRow[1]); } } } if (null != upgradeTable && 0 < upgradeTable.Rows.Count) { bool hasMajorUpgrade = false; foreach (Row row in upgradeTable.Rows) { UpgradeRow upgradeRow = (UpgradeRow)row; if (Compiler.UpgradeDetectedProperty == upgradeRow.ActionProperty) { hasMajorUpgrade = true; int attr = upgradeRow.Attributes; string removeFeatures = upgradeRow.Remove; if (MsiInterop.MsidbUpgradeAttributesVersionMaxInclusive == (attr & MsiInterop.MsidbUpgradeAttributesVersionMaxInclusive)) { majorUpgrade.AllowSameVersionUpgrades = Wix.YesNoType.yes; } if (MsiInterop.MsidbUpgradeAttributesMigrateFeatures != (attr & MsiInterop.MsidbUpgradeAttributesMigrateFeatures)) { majorUpgrade.MigrateFeatures = Wix.YesNoType.no; } if (MsiInterop.MsidbUpgradeAttributesIgnoreRemoveFailure == (attr & MsiInterop.MsidbUpgradeAttributesIgnoreRemoveFailure)) { majorUpgrade.IgnoreRemoveFailure = Wix.YesNoType.yes; } if (!String.IsNullOrEmpty(removeFeatures)) { majorUpgrade.RemoveFeatures = removeFeatures; } } else if (Compiler.DowngradeDetectedProperty == upgradeRow.ActionProperty) { hasMajorUpgrade = true; majorUpgrade.DowngradeErrorMessage = downgradeErrorMessage; } } if (hasMajorUpgrade) { if (String.IsNullOrEmpty(downgradeErrorMessage)) { majorUpgrade.AllowDowngrades = Wix.YesNoType.yes; } if (!String.IsNullOrEmpty(disallowUpgradeErrorMessage)) { majorUpgrade.Disallow = Wix.YesNoType.yes; majorUpgrade.DisallowUpgradeErrorMessage = disallowUpgradeErrorMessage; } majorUpgrade.Schedule = DetermineMajorUpgradeScheduling(tables); this.core.RootElement.AddChild(majorUpgrade); } } }
/// <summary> /// Finalize the search tables. /// </summary> /// <param name="tables">The collection of all tables.</param> /// <remarks>Does all the complex linking required for the search tables.</remarks> private void FinalizeSearchTables(TableCollection tables) { Table appSearchTable = tables["AppSearch"]; Table ccpSearchTable = tables["CCPSearch"]; Table drLocatorTable = tables["DrLocator"]; Hashtable appSearches = new Hashtable(); Hashtable ccpSearches = new Hashtable(); Hashtable drLocators = new Hashtable(); Hashtable locators = new Hashtable(); Hashtable usedSearchElements = new Hashtable(); ArrayList unusedSearchElements = new ArrayList(); Wix.ComplianceCheck complianceCheck = null; // index the AppSearch table by signatures if (null != appSearchTable) { foreach (Row row in appSearchTable.Rows) { string property = Convert.ToString(row[0]); string signature = Convert.ToString(row[1]); if (!appSearches.Contains(signature)) { appSearches.Add(signature, new StringCollection()); } ((StringCollection)appSearches[signature]).Add(property); } } // index the CCPSearch table by signatures if (null != ccpSearchTable) { foreach (Row row in ccpSearchTable.Rows) { string signature = Convert.ToString(row[0]); if (!ccpSearches.Contains(signature)) { ccpSearches.Add(signature, new StringCollection()); } ((StringCollection)ccpSearches[signature]).Add(null); if (null == complianceCheck && !appSearches.Contains(signature)) { complianceCheck = new Wix.ComplianceCheck(); this.core.RootElement.AddChild(complianceCheck); } } } // index the directory searches by their search elements (to get back the original row) if (null != drLocatorTable) { foreach (Row row in drLocatorTable.Rows) { drLocators.Add(this.core.GetIndexedElement(row), row); } } // index the locator tables by their signatures string[] locatorTableNames = new string[] { "CompLocator", "RegLocator", "IniLocator", "DrLocator", "Signature" }; foreach (string locatorTableName in locatorTableNames) { Table locatorTable = tables[locatorTableName]; if (null != locatorTable) { foreach (Row row in locatorTable.Rows) { string signature = Convert.ToString(row[0]); if (!locators.Contains(signature)) { locators.Add(signature, new ArrayList()); } ((ArrayList)locators[signature]).Add(row); } } } // move the DrLocator rows with a parent of CCP_DRIVE first to ensure they get FileSearch children (not FileSearchRef) foreach (ArrayList locatorRows in locators.Values) { int firstDrLocator = -1; for (int i = 0; i < locatorRows.Count; i++) { Row locatorRow = (Row)locatorRows[i]; if ("DrLocator" == locatorRow.TableDefinition.Name) { if (-1 == firstDrLocator) { firstDrLocator = i; } if ("CCP_DRIVE" == Convert.ToString(locatorRow[1])) { locatorRows.RemoveAt(i); locatorRows.Insert(firstDrLocator, locatorRow); break; } } } } foreach (string signature in locators.Keys) { ArrayList locatorRows = (ArrayList)locators[signature]; ArrayList signatureSearchElements = new ArrayList(); foreach (Row locatorRow in locatorRows) { bool used = true; Wix.ISchemaElement searchElement = this.core.GetIndexedElement(locatorRow); if ("Signature" == locatorRow.TableDefinition.Name && 0 < signatureSearchElements.Count) { foreach (Wix.IParentElement searchParentElement in signatureSearchElements) { if (!usedSearchElements.Contains(searchElement)) { searchParentElement.AddChild(searchElement); usedSearchElements[searchElement] = null; } else { Wix.FileSearchRef fileSearchRef = new Wix.FileSearchRef(); fileSearchRef.Id = signature; searchParentElement.AddChild(fileSearchRef); } } } else if ("DrLocator" == locatorRow.TableDefinition.Name && null != locatorRow[1]) { string parentSignature = Convert.ToString(locatorRow[1]); if ("CCP_DRIVE" == parentSignature) { if (appSearches.Contains(signature)) { StringCollection appSearchPropertyIds = (StringCollection)appSearches[signature]; foreach (string propertyId in appSearchPropertyIds) { Wix.Property property = this.EnsureProperty(propertyId); Wix.ComplianceDrive complianceDrive = null; if (ccpSearches.Contains(signature)) { property.ComplianceCheck = Wix.YesNoType.yes; } foreach (Wix.ISchemaElement element in property.Children) { complianceDrive = element as Wix.ComplianceDrive; if (null != complianceDrive) { break; } } if (null == complianceDrive) { complianceDrive = new Wix.ComplianceDrive(); property.AddChild(complianceDrive); } if (!usedSearchElements.Contains(searchElement)) { complianceDrive.AddChild(searchElement); usedSearchElements[searchElement] = null; } else { Wix.DirectorySearchRef directorySearchRef = new Wix.DirectorySearchRef(); directorySearchRef.Id = signature; if (null != locatorRow[1]) { directorySearchRef.Parent = Convert.ToString(locatorRow[1]); } if (null != locatorRow[2]) { directorySearchRef.Path = Convert.ToString(locatorRow[2]); } complianceDrive.AddChild(directorySearchRef); signatureSearchElements.Add(directorySearchRef); } } } else if (ccpSearches.Contains(signature)) { Wix.ComplianceDrive complianceDrive = null; foreach (Wix.ISchemaElement element in complianceCheck.Children) { complianceDrive = element as Wix.ComplianceDrive; if (null != complianceDrive) { break; } } if (null == complianceDrive) { complianceDrive = new Wix.ComplianceDrive(); complianceCheck.AddChild(complianceDrive); } if (!usedSearchElements.Contains(searchElement)) { complianceDrive.AddChild(searchElement); usedSearchElements[searchElement] = null; } else { Wix.DirectorySearchRef directorySearchRef = new Wix.DirectorySearchRef(); directorySearchRef.Id = signature; if (null != locatorRow[1]) { directorySearchRef.Parent = Convert.ToString(locatorRow[1]); } if (null != locatorRow[2]) { directorySearchRef.Path = Convert.ToString(locatorRow[2]); } complianceDrive.AddChild(directorySearchRef); signatureSearchElements.Add(directorySearchRef); } } } else { bool usedDrLocator = false; ArrayList parentLocatorRows = (ArrayList)locators[parentSignature]; if (null != parentLocatorRows) { foreach (Row parentLocatorRow in parentLocatorRows) { if ("DrLocator" == parentLocatorRow.TableDefinition.Name) { Wix.IParentElement parentSearchElement = (Wix.IParentElement)this.core.GetIndexedElement(parentLocatorRow); if (parentSearchElement.Children.GetEnumerator().MoveNext()) { Row parentDrLocatorRow = (Row)drLocators[parentSearchElement]; Wix.DirectorySearchRef directorySeachRef = new Wix.DirectorySearchRef(); directorySeachRef.Id = parentSignature; if (null != parentDrLocatorRow[1]) { directorySeachRef.Parent = Convert.ToString(parentDrLocatorRow[1]); } if (null != parentDrLocatorRow[2]) { directorySeachRef.Path = Convert.ToString(parentDrLocatorRow[2]); } parentSearchElement = directorySeachRef; unusedSearchElements.Add(directorySeachRef); } if (!usedSearchElements.Contains(searchElement)) { parentSearchElement.AddChild(searchElement); usedSearchElements[searchElement] = null; usedDrLocator = true; } else { Wix.DirectorySearchRef directorySearchRef = new Wix.DirectorySearchRef(); directorySearchRef.Id = signature; directorySearchRef.Parent = parentSignature; if (null != locatorRow[2]) { directorySearchRef.Path = Convert.ToString(locatorRow[2]); } parentSearchElement.AddChild(searchElement); usedDrLocator = true; } } } // keep track of unused DrLocator rows if (!usedDrLocator) { unusedSearchElements.Add(searchElement); } } else { // TODO: warn } } } else if (appSearches.Contains(signature)) { StringCollection appSearchPropertyIds = (StringCollection)appSearches[signature]; foreach (string propertyId in appSearchPropertyIds) { Wix.Property property = this.EnsureProperty(propertyId); if (ccpSearches.Contains(signature)) { property.ComplianceCheck = Wix.YesNoType.yes; } if (!usedSearchElements.Contains(searchElement)) { property.AddChild(searchElement); usedSearchElements[searchElement] = null; } else if ("RegLocator" == locatorRow.TableDefinition.Name) { Wix.RegistrySearchRef registrySearchRef = new Wix.RegistrySearchRef(); registrySearchRef.Id = signature; property.AddChild(registrySearchRef); signatureSearchElements.Add(registrySearchRef); } else { // TODO: warn about unavailable Ref element } } } else if (ccpSearches.Contains(signature)) { if (!usedSearchElements.Contains(searchElement)) { complianceCheck.AddChild(searchElement); usedSearchElements[searchElement] = null; } else if ("RegLocator" == locatorRow.TableDefinition.Name) { Wix.RegistrySearchRef registrySearchRef = new Wix.RegistrySearchRef(); registrySearchRef.Id = signature; complianceCheck.AddChild(registrySearchRef); signatureSearchElements.Add(registrySearchRef); } else { // TODO: warn about unavailable Ref element } } else { if ("DrLocator" == locatorRow.TableDefinition.Name) { unusedSearchElements.Add(searchElement); } else { // TODO: warn used = false; } } // keep track of the search elements for this signature so that nested searches go in the proper parents if (used) { signatureSearchElements.Add(searchElement); } } } foreach (Wix.IParentElement unusedSearchElement in unusedSearchElements) { bool used = false; foreach (Wix.ISchemaElement schemaElement in unusedSearchElement.Children) { Wix.DirectorySearch directorySearch = schemaElement as Wix.DirectorySearch; if (null != directorySearch) { StringCollection appSearchProperties = (StringCollection)appSearches[directorySearch.Id]; Wix.ISchemaElement unusedSearchSchemaElement = unusedSearchElement as Wix.ISchemaElement; if (null != appSearchProperties) { Wix.Property property = this.EnsureProperty(appSearchProperties[0]); property.AddChild(unusedSearchSchemaElement); used = true; break; } else if (ccpSearches.Contains(directorySearch.Id)) { complianceCheck.AddChild(unusedSearchSchemaElement); used = true; break; } else { // TODO: warn } } } if (!used) { // TODO: warn } } }
/// <summary> /// Finalize the RemoveFile table. /// </summary> /// <param name="tables">The collection of all tables.</param> /// <remarks> /// Sets the directory/property for each RemoveFile row. /// </remarks> private void FinalizeRemoveFileTable(TableCollection tables) { Table removeFileTable = tables["RemoveFile"]; if (null != removeFileTable) { foreach (Row row in removeFileTable.Rows) { bool isDirectory = false; string property = Convert.ToString(row[3]); // determine if the property is actually authored as a directory if (null != this.core.GetIndexedElement("Directory", property)) { isDirectory = true; } Wix.ISchemaElement element = this.core.GetIndexedElement(row); Wix.RemoveFile removeFile = element as Wix.RemoveFile; if (null != removeFile) { if (isDirectory) { removeFile.Directory = property; } else { removeFile.Property = property; } } else { Wix.RemoveFolder removeFolder = (Wix.RemoveFolder)element; if (isDirectory) { removeFolder.Directory = property; } else { removeFolder.Property = property; } } } } }
/// <summary> /// Finalize the ProgId table. /// </summary> /// <param name="tables">The collection of all tables.</param> /// <remarks> /// Enumerates through all the Class rows, looking for child ProgIds (these are the /// default ProgIds for a given Class). Then go through the ProgId table and add any /// remaining ProgIds for each Class. This happens during finalize because there is /// a circular dependency between the Class and ProgId tables. /// </remarks> private void FinalizeProgIdTable(TableCollection tables) { Table classTable = tables["Class"]; Table progIdTable = tables["ProgId"]; Table extensionTable = tables["Extension"]; Table componentTable = tables["Component"]; Hashtable addedProgIds = new Hashtable(); Hashtable classes = new Hashtable(); Hashtable components = new Hashtable(); // add the default ProgIds for each class (and index the class table) if (null != classTable) { foreach (Row row in classTable.Rows) { Wix.Class wixClass = (Wix.Class)this.core.GetIndexedElement(row); if (null != row[3]) { Wix.ProgId progId = (Wix.ProgId)this.core.GetIndexedElement("ProgId", Convert.ToString(row[3])); if (null != progId) { if (addedProgIds.Contains(progId)) { this.core.OnMessage(WixWarnings.TooManyProgIds(row.SourceLineNumbers, Convert.ToString(row[0]), Convert.ToString(row[3]), Convert.ToString(addedProgIds[progId]))); } else { wixClass.AddChild(progId); addedProgIds.Add(progId, wixClass.Id); } } else { this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, "Class", row.GetPrimaryKey(DecompilerCore.PrimaryKeyDelimiter), "ProgId_Default", Convert.ToString(row[3]), "ProgId")); } } // index the Class elements for nesting of ProgId elements (which don't use the full Class primary key) if (!classes.Contains(wixClass.Id)) { classes.Add(wixClass.Id, new ArrayList()); } ((ArrayList)classes[wixClass.Id]).Add(wixClass); } } // add the remaining non-default ProgId entries for each class if (null != progIdTable) { foreach (Row row in progIdTable.Rows) { Wix.ProgId progId = (Wix.ProgId)this.core.GetIndexedElement(row); if (!addedProgIds.Contains(progId) && null != row[2] && null == progId.ParentElement) { ArrayList classElements = (ArrayList)classes[row[2]]; if (null != classElements) { foreach (Wix.Class wixClass in classElements) { wixClass.AddChild(progId); addedProgIds.Add(progId, wixClass.Id); } } else { this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, "ProgId", row.GetPrimaryKey(DecompilerCore.PrimaryKeyDelimiter), "Class_", Convert.ToString(row[2]), "Class")); } } } } if (null != componentTable) { foreach (Row row in componentTable.Rows) { Wix.Component wixComponent = (Wix.Component)this.core.GetIndexedElement(row); // index the Class elements for nesting of ProgId elements (which don't use the full Class primary key) if (!components.Contains(wixComponent.Id)) { components.Add(wixComponent.Id, new ArrayList()); } ((ArrayList)components[wixComponent.Id]).Add(wixComponent); } } // Check for any progIds that are not hooked up to a class and hook them up to the component specified by the extension if (null != extensionTable) { foreach (Row row in extensionTable.Rows) { // ignore the extension if it isn't associated with a progId if (null == row[2]) { continue; } Wix.ProgId progId = (Wix.ProgId)this.core.GetIndexedElement("ProgId", Convert.ToString(row[2])); // Haven't added the progId yet and it doesn't have a parent progId if (!addedProgIds.Contains(progId) && null == progId.ParentElement) { ArrayList componentElements = (ArrayList)components[row[1]]; if (null != componentElements) { foreach (Wix.Component wixComponent in componentElements) { wixComponent.AddChild(progId); } } else { this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, "Extension", row.GetPrimaryKey(DecompilerCore.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[1]), "Component")); } } } } }
/// <summary> /// Finalize decompilation. /// </summary> /// <param name="tables">The collection of all tables.</param> public virtual void FinalizeDecompile(TableCollection tables) { }
/// <summary> /// Resolve source fields in the tables included in the output /// </summary> /// <param name="tables">The tables to resolve.</param> /// <param name="cabinets">Cabinets containing files that need to be patched.</param> /// <param name="delayedFields">The collection of delayed fields. Null if resolution of delayed fields is not allowed</param> private void ResolveFields(TableCollection tables, Hashtable cabinets, ArrayList delayedFields) { foreach (Table table in tables) { foreach (Row row in table.Rows) { foreach (Field field in row.Fields) { bool isDefault = true; bool delayedResolve = false; // Check to make sure we're in a scenario where we can handle variable resolution. if (null != delayedFields) { // resolve localization and wix variables if (field.Data is string) { field.Data = this.WixVariableResolver.ResolveVariables(row.SourceLineNumbers, (string)field.Data, false, ref isDefault, ref delayedResolve); if (delayedResolve) { delayedFields.Add(new DelayedField(row, field)); } } } // resolve file paths if (!this.WixVariableResolver.EncounteredError && ColumnType.Object == field.Column.Type) { ObjectField objectField = (ObjectField)field; // skip file resolution if the file is to be deleted if (RowOperation.Delete == row.Operation) { continue; } // file is compressed in a cabinet (and not modified above) if (null != objectField.CabinetFileId && isDefault) { // index cabinets that have not been previously encountered if (!cabinets.ContainsKey(objectField.BaseUri)) { Uri baseUri = new Uri(objectField.BaseUri); string localFileNameWithoutExtension = Path.GetFileNameWithoutExtension(baseUri.LocalPath); string extractedDirectoryName = String.Format(CultureInfo.InvariantCulture, "cab_{0}_{1}", cabinets.Count, localFileNameWithoutExtension); // index the cabinet file's base URI (source location) and extracted directory cabinets.Add(objectField.BaseUri, Path.Combine(this.TempFilesLocation, extractedDirectoryName)); } // set the path to the file once its extracted from the cabinet objectField.Data = Path.Combine((string)cabinets[objectField.BaseUri], objectField.CabinetFileId); } else if (null != objectField.Data) // non-compressed file (or localized value) { // when SuppressFileHasAndInfo is true do not resolve file paths if (this.suppressFileHashAndInfo && table.Name == "WixFile") { continue; } try { if (OutputType.Patch != this.FileManager.Output.Type) // Normal binding for non-Patch scenario such as link (light.exe) { // keep a copy of the un-resolved data for future replay. This will be saved into wixpdb file if (null == objectField.UnresolvedData) { objectField.UnresolvedData = (string)objectField.Data; } // resolve the path to the file objectField.Data = this.FileManager.ResolveFile((string)objectField.Data, table.Name, row.SourceLineNumbers, BindStage.Normal); } else if (!(this.FileManager.ReBaseTarget || this.FileManager.ReBaseUpdated)) // Normal binding for Patch Scenario (normal patch, no re-basing logic) { // resolve the path to the file objectField.Data = this.FileManager.ResolveFile((string)objectField.Data, table.Name, row.SourceLineNumbers, BindStage.Normal); } else // Re-base binding path scenario caused by pyro.exe -bt -bu { // by default, use the resolved Data for file lookup string filePathToResolve = (string)objectField.Data; // if -bu is used in pyro command, this condition holds true and the tool // will use pre-resolved source for new wixpdb file if (this.FileManager.ReBaseUpdated) { // try to use the unResolved Source if it exists. // New version of wixpdb file keeps a copy of pre-resolved Source. i.e. !(bindpath.test)\foo.dll // Old version of winpdb file does not contain this attribute and the value is null. if (null != objectField.UnresolvedData) { filePathToResolve = objectField.UnresolvedData; } } objectField.Data = this.FileManager.ResolveFile(filePathToResolve, table.Name, row.SourceLineNumbers, BindStage.Updated); } } catch (WixFileNotFoundException) { // display the error with source line information this.core.OnMessage(WixErrors.FileNotFound(row.SourceLineNumbers, (string)objectField.Data)); } } isDefault = true; if (null != objectField.PreviousData) { objectField.PreviousData = this.WixVariableResolver.ResolveVariables(row.SourceLineNumbers, objectField.PreviousData, false, ref isDefault); if (!this.WixVariableResolver.EncounteredError) { // file is compressed in a cabinet (and not modified above) if (null != objectField.PreviousCabinetFileId && isDefault) { // when loading transforms from disk, PreviousBaseUri may not have been set if (null == objectField.PreviousBaseUri) { objectField.PreviousBaseUri = objectField.BaseUri; } // index cabinets that have not been previously encountered if (!cabinets.ContainsKey(objectField.PreviousBaseUri)) { Uri baseUri = new Uri(objectField.PreviousBaseUri); string localFileNameWithoutExtension = Path.GetFileNameWithoutExtension(baseUri.LocalPath); string extractedDirectoryName = String.Format(CultureInfo.InvariantCulture, "cab_{0}_{1}", cabinets.Count, localFileNameWithoutExtension); // index the cabinet file's base URI (source location) and extracted directory cabinets.Add(objectField.PreviousBaseUri, Path.Combine(this.TempFilesLocation, extractedDirectoryName)); } // set the path to the file once its extracted from the cabinet objectField.PreviousData = Path.Combine((string)cabinets[objectField.PreviousBaseUri], objectField.PreviousCabinetFileId); } else if (null != objectField.PreviousData) // non-compressed file (or localized value) { // when SuppressFileHasAndInfo is true do not resolve file paths if (this.suppressFileHashAndInfo && table.Name == "WixFile") { continue; } try { if (!this.FileManager.ReBaseTarget && !this.FileManager.ReBaseUpdated) { // resolve the path to the file objectField.PreviousData = this.FileManager.ResolveFile((string)objectField.PreviousData, table.Name, row.SourceLineNumbers, BindStage.Normal); } else { if (this.FileManager.ReBaseTarget) { // if -bt is used, it come here // Try to use the original unresolved source from either target build or update build // If both target and updated are of old wixpdb, it behaves the same as today, no re-base logic here // If target is old version and updated is new version, it uses unresolved path from updated build // If both target and updated are of new versions, it uses unresolved path from target build if (null != objectField.UnresolvedPreviousData || null != objectField.UnresolvedData) { objectField.PreviousData = objectField.UnresolvedPreviousData ?? objectField.UnresolvedData; } } // resolve the path to the file objectField.PreviousData = this.FileManager.ResolveFile((string)objectField.PreviousData, table.Name, row.SourceLineNumbers, BindStage.Target); } } catch (WixFileNotFoundException) { // display the error with source line information this.core.OnMessage(WixErrors.FileNotFound(row.SourceLineNumbers, (string)objectField.PreviousData)); } } } } } } } } // remember if the variable resolver found an error if (this.WixVariableResolver.EncounteredError) { this.core.EncounteredError = true; } }
/// <summary> /// Merge data from the unreal tables into the real tables. /// </summary> /// <param name="tables">Collection of all tables.</param> private void MergeUnrealTables(TableCollection tables) { // merge data from the WixBBControl rows into the BBControl rows Table wixBBControlTable = tables["WixBBControl"]; Table bbControlTable = tables["BBControl"]; if (null != wixBBControlTable && null != bbControlTable) { // index all the BBControl rows by their identifier Hashtable indexedBBControlRows = new Hashtable(bbControlTable.Rows.Count); foreach (BBControlRow bbControlRow in bbControlTable.Rows) { indexedBBControlRows.Add(bbControlRow.GetPrimaryKey('/'), bbControlRow); } foreach (Row row in wixBBControlTable.Rows) { BBControlRow bbControlRow = (BBControlRow)indexedBBControlRows[row.GetPrimaryKey('/')]; bbControlRow.SourceFile = (string)row[2]; } } // merge data from the WixControl rows into the Control rows Table wixControlTable = tables["WixControl"]; Table controlTable = tables["Control"]; if (null != wixControlTable && null != controlTable) { // index all the Control rows by their identifier Hashtable indexedControlRows = new Hashtable(controlTable.Rows.Count); foreach (ControlRow controlRow in controlTable.Rows) { indexedControlRows.Add(controlRow.GetPrimaryKey('/'), controlRow); } foreach (Row row in wixControlTable.Rows) { ControlRow controlRow = (ControlRow)indexedControlRows[row.GetPrimaryKey('/')]; controlRow.SourceFile = (string)row[2]; } } // merge data from the WixFile rows into the File rows Table wixFileTable = tables["WixFile"]; Table fileTable = tables["File"]; if (null != wixFileTable && null != fileTable) { // index all the File rows by their identifier Hashtable indexedFileRows = new Hashtable(fileTable.Rows.Count, StringComparer.OrdinalIgnoreCase); foreach (FileRow fileRow in fileTable.Rows) { try { indexedFileRows.Add(fileRow.File, fileRow); } catch (ArgumentException) { this.core.OnMessage(WixErrors.DuplicateFileId(fileRow.File)); } } if (this.core.EncounteredError) { return; } foreach (WixFileRow row in wixFileTable.Rows) { FileRow fileRow = (FileRow)indexedFileRows[row.File]; if (null != row[1]) { fileRow.AssemblyType = (FileAssemblyType)Enum.ToObject(typeof(FileAssemblyType), row.AssemblyAttributes); } else { fileRow.AssemblyType = FileAssemblyType.NotAnAssembly; } fileRow.AssemblyApplication = row.AssemblyApplication; fileRow.AssemblyManifest = row.AssemblyManifest; fileRow.Directory = row.Directory; fileRow.DiskId = row.DiskId; fileRow.Source = row.Source; fileRow.PreviousSource = row.PreviousSource; fileRow.ProcessorArchitecture = row.ProcessorArchitecture; fileRow.PatchGroup = row.PatchGroup; fileRow.PatchAttributes = row.PatchAttributes; fileRow.RetainLengths = row.RetainLengths; fileRow.IgnoreOffsets = row.IgnoreOffsets; fileRow.IgnoreLengths = row.IgnoreLengths; fileRow.RetainOffsets = row.RetainOffsets; fileRow.PreviousRetainLengths = row.PreviousRetainLengths; fileRow.PreviousIgnoreOffsets = row.PreviousIgnoreOffsets; fileRow.PreviousIgnoreLengths = row.PreviousIgnoreLengths; fileRow.PreviousRetainOffsets = row.PreviousRetainOffsets; } } // merge data from the WixPatchSymbolPaths rows into the File rows Table wixPatchSymbolPathsTable = tables["WixPatchSymbolPaths"]; Table mediaTable = tables["Media"]; Table directoryTable = tables["Directory"]; Table componentTable = tables["Component"]; if (null != wixPatchSymbolPathsTable) { int fileRowNum = (null != fileTable) ? fileTable.Rows.Count : 0; int componentRowNum = (null != fileTable) ? componentTable.Rows.Count : 0; int directoryRowNum = (null != directoryTable) ? directoryTable.Rows.Count : 0; int mediaRowNum = (null != mediaTable) ? mediaTable.Rows.Count : 0; Hashtable fileRowsByFile = new Hashtable(fileRowNum); Hashtable fileRowsByComponent = new Hashtable(componentRowNum); Hashtable fileRowsByDirectory = new Hashtable(directoryRowNum); Hashtable fileRowsByDiskId = new Hashtable(mediaRowNum); // index all the File rows by their identifier if (null != fileTable) { foreach (FileRow fileRow in fileTable.Rows) { fileRowsByFile.Add(fileRow.File, fileRow); ArrayList fileRows = (ArrayList)fileRowsByComponent[fileRow.Component]; if (null == fileRows) { fileRows = new ArrayList(); fileRowsByComponent.Add(fileRow.Component, fileRows); } fileRows.Add(fileRow); fileRows = (ArrayList)fileRowsByDirectory[fileRow.Directory]; if (null == fileRows) { fileRows = new ArrayList(); fileRowsByDirectory.Add(fileRow.Directory, fileRows); } fileRows.Add(fileRow); fileRows = (ArrayList)fileRowsByDiskId[fileRow.DiskId]; if (null == fileRows) { fileRows = new ArrayList(); fileRowsByDiskId.Add(fileRow.DiskId, fileRows); } fileRows.Add(fileRow); } } wixPatchSymbolPathsTable.Rows.Sort(new WixPatchSymbolPathsComparer()); foreach (Row row in wixPatchSymbolPathsTable.Rows) { switch ((string)row[0]) { case "File": MergeSymbolPaths(row, (FileRow)fileRowsByFile[row[1]]); break; case "Product": foreach (FileRow fileRow in fileRowsByFile) { MergeSymbolPaths(row, fileRow); } break; case "Component": ArrayList fileRowsByThisComponent = (ArrayList)(fileRowsByComponent[row[1]]); if (null != fileRowsByThisComponent) { foreach (FileRow fileRow in fileRowsByThisComponent) { MergeSymbolPaths(row, fileRow); } } break; case "Directory": ArrayList fileRowsByThisDirectory = (ArrayList)(fileRowsByDirectory[row[1]]); if (null != fileRowsByThisDirectory) { foreach (FileRow fileRow in fileRowsByThisDirectory) { MergeSymbolPaths(row, fileRow); } } break; case "Media": ArrayList fileRowsByThisDiskId = (ArrayList)(fileRowsByDiskId[row[1]]); if (null != fileRowsByThisDiskId) { foreach (FileRow fileRow in fileRowsByThisDiskId) { MergeSymbolPaths(row, fileRow); } } break; default: // error break; } } } // copy data from the WixMedia rows into the Media rows Table wixMediaTable = tables["WixMedia"]; if (null != wixMediaTable && null != mediaTable) { // index all the Media rows by their identifier Hashtable indexedMediaRows = new Hashtable(mediaTable.Rows.Count); foreach (MediaRow mediaRow in mediaTable.Rows) { indexedMediaRows.Add(mediaRow.DiskId, mediaRow); } foreach (Row row in wixMediaTable.Rows) { MediaRow mediaRow = (MediaRow)indexedMediaRows[row[0]]; // compression level if (null != row[1]) { mediaRow.CompressionLevel = WixCreateCab.CompressionLevelFromString((string)row[1]); } // layout if (null != row[2]) { mediaRow.Layout = (string)row[2]; } } } }
/// <summary> /// Localize dialogs and controls. /// </summary> /// <param name="tables">The tables to localize.</param> private void LocalizeUI(TableCollection tables) { Table dialogTable = tables["Dialog"]; if (null != dialogTable) { foreach (Row row in dialogTable.Rows) { string dialog = (string)row[0]; LocalizedControl localizedControl = this.Localizer.GetLocalizedControl(dialog, null); if (null != localizedControl) { if (CompilerCore.IntegerNotSet != localizedControl.X) { row[1] = localizedControl.X; } if (CompilerCore.IntegerNotSet != localizedControl.Y) { row[2] = localizedControl.Y; } if (CompilerCore.IntegerNotSet != localizedControl.Width) { row[3] = localizedControl.Width; } if (CompilerCore.IntegerNotSet != localizedControl.Height) { row[4] = localizedControl.Height; } row[5] = (int)row[5] | localizedControl.Attributes; if (!String.IsNullOrEmpty(localizedControl.Text)) { row[6] = localizedControl.Text; } } } } Table controlTable = tables["Control"]; if (null != controlTable) { foreach (Row row in controlTable.Rows) { string dialog = (string)row[0]; string control = (string)row[1]; LocalizedControl localizedControl = this.Localizer.GetLocalizedControl(dialog, control); if (null != localizedControl) { if (CompilerCore.IntegerNotSet != localizedControl.X) { row[3] = localizedControl.X.ToString(); } if (CompilerCore.IntegerNotSet != localizedControl.Y) { row[4] = localizedControl.Y.ToString(); } if (CompilerCore.IntegerNotSet != localizedControl.Width) { row[5] = localizedControl.Width.ToString(); } if (CompilerCore.IntegerNotSet != localizedControl.Height) { row[6] = localizedControl.Height.ToString(); } row[7] = (int)row[7] | localizedControl.Attributes; if (!String.IsNullOrEmpty(localizedControl.Text)) { row[9] = localizedControl.Text; } } } } }
/// <summary> /// Finalize the File table. /// </summary> /// <param name="tables">The collection of all tables.</param> /// <remarks> /// Sets the source, diskId, and assembly information for each file. /// </remarks> private void FinalizeFileTable(TableCollection tables) { Table fileTable = tables["File"]; Table mediaTable = tables["Media"]; Table msiAssemblyTable = tables["MsiAssembly"]; Table typeLibTable = tables["TypeLib"]; MediaRowCollection mediaRows; // index the media table by media id if (null != mediaTable) { mediaRows = new MediaRowCollection(); mediaRows.AddRange(mediaTable.Rows); } // set the disk identifiers and sources for files if (null != fileTable) { foreach (FileRow fileRow in fileTable.Rows) { Wix.File file = (Wix.File)this.core.GetIndexedElement("File", fileRow.File); // Don't bother processing files that are orphaned (and won't show up in the output anyway) if (null != file.ParentElement) { // set the diskid if (null != mediaTable) { foreach (MediaRow mediaRow in mediaTable.Rows) { if (fileRow.Sequence <= mediaRow.LastSequence) { file.DiskId = Convert.ToString(mediaRow.DiskId); break; } } } // set the source (done here because it requires information from the Directory table) if (OutputType.Module == this.outputType) { file.Source = String.Concat(this.exportFilePath, Path.DirectorySeparatorChar, "File", Path.DirectorySeparatorChar, file.Id, '.', this.modularizationGuid.Substring(1, 36).Replace('-', '_')); } else if (Wix.YesNoDefaultType.yes == file.Compressed || (Wix.YesNoDefaultType.no != file.Compressed && this.compressed)) { file.Source = String.Concat(this.exportFilePath, Path.DirectorySeparatorChar, "File", Path.DirectorySeparatorChar, file.Id); } else // uncompressed { string fileName = (null != file.ShortName ? file.ShortName : file.Name); if (!this.shortNames && null != file.Name) { fileName = file.Name; } if (this.compressed) // uncompressed at the root of the source image { file.Source = String.Concat("SourceDir", Path.DirectorySeparatorChar, fileName); } else { string sourcePath = this.GetSourcePath(file); file.Source = Path.Combine(sourcePath, fileName); } } } } } // set the file assemblies and manifests if (null != msiAssemblyTable) { foreach (Row row in msiAssemblyTable.Rows) { Wix.Component component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[0])); if (null == component) { this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, "MsiAssembly", row.GetPrimaryKey(DecompilerCore.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[0]), "Component")); } else { foreach (Wix.ISchemaElement element in component.Children) { Wix.File file = element as Wix.File; if (null != file && Wix.YesNoType.yes == file.KeyPath) { if (null != row[2]) { file.AssemblyManifest = Convert.ToString(row[2]); } if (null != row[3]) { file.AssemblyApplication = Convert.ToString(row[3]); } if (null == row[4] || 0 == Convert.ToInt32(row[4])) { file.Assembly = Wix.File.AssemblyType.net; } else { file.Assembly = Wix.File.AssemblyType.win32; } } } } } } // nest the TypeLib elements if (null != typeLibTable) { foreach (Row row in typeLibTable.Rows) { Wix.Component component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[2])); Wix.TypeLib typeLib = (Wix.TypeLib)this.core.GetIndexedElement(row); foreach (Wix.ISchemaElement element in component.Children) { Wix.File file = element as Wix.File; if (null != file && Wix.YesNoType.yes == file.KeyPath) { file.AddChild(typeLib); } } } } }
/// <summary> /// Finalize the MIME table. /// </summary> /// <param name="tables">The collection of all tables.</param> /// <remarks> /// There is a foreign key shared between the MIME and Extension /// tables so either one would be valid to be decompiled first, so /// the only safe way to nest the MIME elements is to do it during finalize. /// </remarks> private void FinalizeMIMETable(TableCollection tables) { Table extensionTable = tables["Extension"]; Table mimeTable = tables["MIME"]; Hashtable comExtensions = new Hashtable(); if (null != extensionTable) { foreach (Row row in extensionTable.Rows) { Wix.Extension extension = (Wix.Extension)this.core.GetIndexedElement(row); // index the extension if (!comExtensions.Contains(row[0])) { comExtensions.Add(row[0], new ArrayList()); } ((ArrayList)comExtensions[row[0]]).Add(extension); // set the default MIME element for this extension if (null != row[3]) { Wix.MIME mime = (Wix.MIME)this.core.GetIndexedElement("MIME", Convert.ToString(row[3])); if (null != mime) { mime.Default = Wix.YesNoType.yes; } else { this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, "Extension", row.GetPrimaryKey(DecompilerCore.PrimaryKeyDelimiter), "MIME_", Convert.ToString(row[3]), "MIME")); } } } } if (null != mimeTable) { foreach (Row row in mimeTable.Rows) { Wix.MIME mime = (Wix.MIME)this.core.GetIndexedElement(row); if (comExtensions.Contains(row[1])) { ArrayList extensionElements = (ArrayList)comExtensions[row[1]]; foreach (Wix.Extension extension in extensionElements) { extension.AddChild(mime); } } else { this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, "MIME", row.GetPrimaryKey(DecompilerCore.PrimaryKeyDelimiter), "Extension_", Convert.ToString(row[1]), "Extension")); } } } }
/// <summary> /// Resolves paths to files. /// </summary> /// <param name="sectionTables">TableCollection of tables to process</param> /// <param name="binderFileManager">If provided, the binder file manager is used to bind files into the output.</param> /// <param name="wixVariableResolver">The Wix variable resolver.</param> /// <param name="tempFilesLocation">Location for temporary files.</param> /// <param name="cabinets">Hash of source cabinets.</param> /// <param name="fileIds">Collection of CabinetFileIds.</param> /// <param name="files">Collection of file paths from compressed files.</param> /// <param name="index">CabinetFileId generator.</param> public static void ResolveSectionFiles(TableCollection sectionTables, BinderFileManager binderFileManager, WixVariableResolver wixVariableResolver, string tempFilesLocation, Hashtable cabinets, StringCollection fileIds, StringCollection files, ref int index) { foreach (Table table in sectionTables) { foreach (Row row in table.Rows) { foreach (Field field in row.Fields) { ObjectField objectField = field as ObjectField; if (null != objectField && null != objectField.Data) { string file = null; string previousFile = null; bool isDefault = true; bool isPreviousDefault = true; // resolve localization and wix variables if there is a file manager that would use the value // if it was different, otherwise we just don't care so skip the whole variable resolution thing. if (null != wixVariableResolver && null != binderFileManager) { objectField.Data = wixVariableResolver.ResolveVariables(row.SourceLineNumbers, (string)objectField.Data, false, ref isDefault); if (null != objectField.PreviousData) { objectField.PreviousData = wixVariableResolver.ResolveVariables(row.SourceLineNumbers, objectField.PreviousData, false, ref isPreviousDefault); } // do not save the output if errors were found while resolving object paths if (wixVariableResolver.EncounteredError) { return; } } // file is compressed in a cabinet (and not modified above) if (null != objectField.CabinetFileId && isDefault) { // index cabinets that have not been previously encountered if (!cabinets.ContainsKey(objectField.BaseUri)) { Uri baseUri = new Uri(objectField.BaseUri); string localFileNameWithoutExtension = Path.GetFileNameWithoutExtension(baseUri.LocalPath); string extractedDirectoryName = String.Format(CultureInfo.InvariantCulture, "cab_{0}_{1}", cabinets.Count, localFileNameWithoutExtension); // index the cabinet file's base URI (source location) and extracted directory cabinets.Add(objectField.BaseUri, Path.Combine(tempFilesLocation, extractedDirectoryName)); } // set the path to the file once its extracted from the cabinet file = Path.Combine((string)cabinets[objectField.BaseUri], objectField.CabinetFileId); } else if (null != binderFileManager) { file = binderFileManager.ResolveFile((string)objectField.Data, table.Name, row.SourceLineNumbers, BindStage.Normal); } // add the file to the list of files to go in the cabinet if (null != file) { string cabinetFileId = (index++).ToString(CultureInfo.InvariantCulture); objectField.CabinetFileId = cabinetFileId; fileIds.Add(cabinetFileId); files.Add(file); } // previous file is compressed in a cabinet (and not modified above) if (null != objectField.PreviousCabinetFileId && isPreviousDefault) { // index cabinets that have not been previously encountered if (!cabinets.ContainsKey(objectField.PreviousBaseUri)) { Uri baseUri = new Uri(objectField.PreviousBaseUri); string localFileNameWithoutExtension = Path.GetFileNameWithoutExtension(baseUri.LocalPath); string extractedDirectoryName = String.Format(CultureInfo.InvariantCulture, "cab_{0}_{1}", cabinets.Count, localFileNameWithoutExtension); // index the cabinet file's base URI (source location) and extracted directory cabinets.Add(objectField.PreviousBaseUri, Path.Combine(tempFilesLocation, extractedDirectoryName)); } // set the path to the file once its extracted from the cabinet previousFile = Path.Combine((string)cabinets[objectField.PreviousBaseUri], objectField.PreviousCabinetFileId); } else if (null != objectField.PreviousData && null != binderFileManager) { previousFile = binderFileManager.ResolveFile((string)objectField.PreviousData, table.Name, row.SourceLineNumbers, BindStage.Normal); } // add the file to the list of files to go in the cabinet if (null != previousFile) { string cabinetFileId = (index++).ToString(CultureInfo.InvariantCulture); objectField.PreviousCabinetFileId = cabinetFileId; fileIds.Add(cabinetFileId); files.Add(previousFile); } } } } } }
/// <summary> /// Finalize the Property table. /// </summary> /// <param name="tables">The collection of all tables.</param> /// <remarks> /// Removes properties that are generated from other entries. /// </remarks> private void FinalizePropertyTable(TableCollection tables) { Table propertyTable = tables["Property"]; Table customActionTable = tables["CustomAction"]; if (null != propertyTable && null != customActionTable) { foreach (Row row in customActionTable.Rows) { int bits = Convert.ToInt32(row[1]); if (MsiInterop.MsidbCustomActionTypeHideTarget == (bits & MsiInterop.MsidbCustomActionTypeHideTarget) && MsiInterop.MsidbCustomActionTypeInScript == (bits & MsiInterop.MsidbCustomActionTypeInScript)) { Wix.Property property = (Wix.Property)this.core.GetIndexedElement("Property", Convert.ToString(row[0])); // If no other fields on the property are set we must have created it during link if (null == property.Value && Wix.YesNoType.yes != property.Secure && Wix.YesNoType.yes != property.SuppressModularization) { this.core.RootElement.RemoveChild(property); } } } } }
/// <summary> /// Resolves paths to files. /// </summary> /// <param name="sectionTables">TableCollection of tables to process</param> /// <param name="binderFileManager">If provided, the binder file manager is used to bind files into the output.</param> /// <param name="wixVariableResolver">The Wix variable resolver.</param> /// <param name="tempFilesLocation">Location for temporary files.</param> /// <param name="cabinets">Hash of source cabinets.</param> /// <param name="fileIds">Collection of CabinetFileIds.</param> /// <param name="files">Collection of file paths from compressed files.</param> /// <param name="index">CabinetFileId generator.</param> public static void ResolveSectionFiles(TableCollection sectionTables, BinderFileManager binderFileManager, WixVariableResolver wixVariableResolver, string tempFilesLocation, Hashtable cabinets, StringCollection fileIds, StringCollection files, ref int index) { foreach (Table table in sectionTables) { foreach (Row row in table.Rows) { foreach (Field field in row.Fields) { ObjectField objectField = field as ObjectField; if (null != objectField && null != objectField.Data) { string file = null; string previousFile = null; bool isDefault = true; bool isPreviousDefault = true; // resolve localization and wix variables if there is a file manager that would use the value // if it was different, otherwise we just don't care so skip the whole variable resolution thing. if (null != wixVariableResolver && null != binderFileManager) { objectField.Data = wixVariableResolver.ResolveVariables(row.SourceLineNumbers, (string)objectField.Data, false, ref isDefault); if (null != objectField.PreviousData) { objectField.PreviousData = wixVariableResolver.ResolveVariables(row.SourceLineNumbers, objectField.PreviousData, false, ref isPreviousDefault); } // do not save the output if errors were found while resolving object paths if (wixVariableResolver.EncounteredError) { return; } } // file is compressed in a cabinet (and not modified above) if (null != objectField.CabinetFileId && isDefault) { // index cabinets that have not been previously encountered if (!cabinets.ContainsKey(objectField.BaseUri)) { Uri baseUri = new Uri(objectField.BaseUri); string localFileNameWithoutExtension = Path.GetFileNameWithoutExtension(baseUri.LocalPath); string extractedDirectoryName = String.Format(CultureInfo.InvariantCulture, "cab_{0}_{1}", cabinets.Count, localFileNameWithoutExtension); // index the cabinet file's base URI (source location) and extracted directory cabinets.Add(objectField.BaseUri, Path.Combine(tempFilesLocation, extractedDirectoryName)); } // set the path to the file once its extracted from the cabinet file = Path.Combine((string)cabinets[objectField.BaseUri], objectField.CabinetFileId); } else if (null != binderFileManager) { file = binderFileManager.ResolveFile((string)objectField.Data, table.Name, row.SourceLineNumbers, BindStage.Normal); } // add the file to the list of files to go in the cabinet if (null != file) { string cabinetFileId = (index++).ToString(CultureInfo.InvariantCulture); objectField.CabinetFileId = cabinetFileId; fileIds.Add(cabinetFileId); files.Add(file); } // previous file is compressed in a cabinet (and not modified above) if (null != objectField.PreviousCabinetFileId && isPreviousDefault) { // index cabinets that have not been previously encountered if (!cabinets.ContainsKey(objectField.PreviousBaseUri)) { Uri baseUri = new Uri(objectField.PreviousBaseUri); string localFileNameWithoutExtension = Path.GetFileNameWithoutExtension(baseUri.LocalPath); string extractedDirectoryName = String.Format(CultureInfo.InvariantCulture, "cab_{0}_{1}", cabinets.Count, localFileNameWithoutExtension); // index the cabinet file's base URI (source location) and extracted directory cabinets.Add(objectField.PreviousBaseUri, Path.Combine(tempFilesLocation, extractedDirectoryName)); } // set the path to the file once its extracted from the cabinet previousFile = Path.Combine((string)cabinets[objectField.PreviousBaseUri], objectField.PreviousCabinetFileId); } else if (null != objectField.PreviousData && null != binderFileManager) { previousFile = binderFileManager.ResolveFile((string)objectField.PreviousData, table.Name, row.SourceLineNumbers, BindStage.Normal); } // add the file to the list of files to go in the cabinet if (null != previousFile) { string cabinetFileId = (index++).ToString(CultureInfo.InvariantCulture); objectField.PreviousCabinetFileId = cabinetFileId; fileIds.Add(cabinetFileId); files.Add(previousFile); } } } } } }
/// <summary> /// Finalize the MsiLockPermissionsEx table. /// </summary> /// <param name="tables">The collection of all tables.</param> /// <remarks> /// Nests the PermissionEx elements below their parent elements. There are no declared foreign /// keys for the parents of the MsiLockPermissionsEx table. /// </remarks> private void FinalizeMsiLockPermissionsExTable(TableCollection tables) { Table createFolderTable = tables["CreateFolder"]; Table msiLockPermissionsExTable = tables["MsiLockPermissionsEx"]; Hashtable createFolders = new Hashtable(); // index the CreateFolder table because the foreign key to this table from the // MsiLockPermissionsEx table is only part of the primary key of this table if (null != createFolderTable) { foreach (Row row in createFolderTable.Rows) { Wix.CreateFolder createFolder = (Wix.CreateFolder)this.core.GetIndexedElement(row); string directoryId = Convert.ToString(row[0]); if (!createFolders.Contains(directoryId)) { createFolders.Add(directoryId, new ArrayList()); } ((ArrayList)createFolders[directoryId]).Add(createFolder); } } if (null != msiLockPermissionsExTable) { foreach (Row row in msiLockPermissionsExTable.Rows) { string id = Convert.ToString(row[1]); string table = Convert.ToString(row[2]); Wix.PermissionEx permissionEx = (Wix.PermissionEx)this.core.GetIndexedElement(row); if ("CreateFolder" == table) { ArrayList createFolderElements = (ArrayList)createFolders[id]; if (null != createFolderElements) { foreach (Wix.CreateFolder createFolder in createFolderElements) { createFolder.AddChild(permissionEx); } } else { this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, "MsiLockPermissionsEx", row.GetPrimaryKey(DecompilerCore.PrimaryKeyDelimiter), "LockObject", id, table)); } } else { Wix.IParentElement parentElement = (Wix.IParentElement)this.core.GetIndexedElement(table, id); if (null != parentElement) { parentElement.AddChild(permissionEx); } else { this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, "MsiLockPermissionsEx", row.GetPrimaryKey(DecompilerCore.PrimaryKeyDelimiter), "LockObject", id, table)); } } } } }
/// <summary> /// Finalize the Component table. /// </summary> /// <param name="tables">The collection of all tables.</param> /// <remarks> /// Set the keypaths for each component. /// </remarks> private void FinalizeComponentTable(TableCollection tables) { Table componentTable = tables["Component"]; Table fileTable = tables["File"]; Table odbcDataSourceTable = tables["ODBCDataSource"]; Table registryTable = tables["Registry"]; // set the component keypaths if (null != componentTable) { foreach (Row row in componentTable.Rows) { int attributes = Convert.ToInt32(row[3]); if (null == row[5]) { Wix.Component component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[0])); component.KeyPath = Wix.YesNoType.yes; } else if (MsiInterop.MsidbComponentAttributesRegistryKeyPath == (attributes & MsiInterop.MsidbComponentAttributesRegistryKeyPath)) { object registryObject = this.core.GetIndexedElement("Registry", Convert.ToString(row[5])); if (null != registryObject) { Wix.RegistryValue registryValue = registryObject as Wix.RegistryValue; if (null != registryValue) { registryValue.KeyPath = Wix.YesNoType.yes; } else { this.core.OnMessage(WixWarnings.IllegalRegistryKeyPath(row.SourceLineNumbers, "Component", Convert.ToString(row[5]))); } } else { this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, "Component", row.GetPrimaryKey(DecompilerCore.PrimaryKeyDelimiter), "KeyPath", Convert.ToString(row[5]), "Registry")); } } else if (MsiInterop.MsidbComponentAttributesODBCDataSource == (attributes & MsiInterop.MsidbComponentAttributesODBCDataSource)) { Wix.ODBCDataSource odbcDataSource = (Wix.ODBCDataSource)this.core.GetIndexedElement("ODBCDataSource", Convert.ToString(row[5])); if (null != odbcDataSource) { odbcDataSource.KeyPath = Wix.YesNoType.yes; } else { this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, "Component", row.GetPrimaryKey(DecompilerCore.PrimaryKeyDelimiter), "KeyPath", Convert.ToString(row[5]), "ODBCDataSource")); } } else { Wix.File file = (Wix.File)this.core.GetIndexedElement("File", Convert.ToString(row[5])); if (null != file) { file.KeyPath = Wix.YesNoType.yes; } else { this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, "Component", row.GetPrimaryKey(DecompilerCore.PrimaryKeyDelimiter), "KeyPath", Convert.ToString(row[5]), "File")); } } } } // add the File children elements if (null != fileTable) { foreach (FileRow fileRow in fileTable.Rows) { Wix.Component component = (Wix.Component)this.core.GetIndexedElement("Component", fileRow.Component); Wix.File file = (Wix.File)this.core.GetIndexedElement(fileRow); if (null != component) { component.AddChild(file); } else { this.core.OnMessage(WixWarnings.ExpectedForeignRow(fileRow.SourceLineNumbers, "File", fileRow.GetPrimaryKey(DecompilerCore.PrimaryKeyDelimiter), "Component_", fileRow.Component, "Component")); } } } // add the ODBCDataSource children elements if (null != odbcDataSourceTable) { foreach (Row row in odbcDataSourceTable.Rows) { Wix.Component component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[1])); Wix.ODBCDataSource odbcDataSource = (Wix.ODBCDataSource)this.core.GetIndexedElement(row); if (null != component) { component.AddChild(odbcDataSource); } else { this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, "ODBCDataSource", row.GetPrimaryKey(DecompilerCore.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[1]), "Component")); } } } // add the Registry children elements if (null != registryTable) { foreach (Row row in registryTable.Rows) { Wix.Component component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[5])); Wix.ISchemaElement registryElement = (Wix.ISchemaElement)this.core.GetIndexedElement(row); if (null != component) { component.AddChild(registryElement); } else { this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, "Registry", row.GetPrimaryKey(DecompilerCore.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[5]), "Component")); } } } }
/// <summary> /// Finalize the sequence tables. /// </summary> /// <param name="tables">The collection of all tables.</param> /// <remarks> /// Creates the sequence elements. Occurs during finalization because its /// not known if sequences refer to custom actions or dialogs during decompilation. /// </remarks> private void FinalizeSequenceTables(TableCollection tables) { // finalize the normal sequence tables if (OutputType.Product == this.outputType && !this.treatProductAsModule) { foreach (SequenceTable sequenceTable in Enum.GetValues(typeof(SequenceTable))) { // if suppressing UI elements, skip UI-related sequence tables if (this.suppressUI && ("AdminUISequence" == sequenceTable.ToString() || "InstallUISequence" == sequenceTable.ToString())) { continue; } Table actionsTable = new Table(null, this.tableDefinitions["WixAction"]); Table table = tables[sequenceTable.ToString()]; if (null != table) { ArrayList actionRows = new ArrayList(); bool needAbsoluteScheduling = this.suppressRelativeActionSequencing; WixActionRowCollection nonSequencedActionRows = new WixActionRowCollection(); WixActionRowCollection suppressedRelativeActionRows = new WixActionRowCollection(); // create a sorted array of actions in this table foreach (Row row in table.Rows) { WixActionRow actionRow = (WixActionRow)actionsTable.CreateRow(null); actionRow.Action = Convert.ToString(row[0]); if (null != row[1]) { actionRow.Condition = Convert.ToString(row[1]); } actionRow.Sequence = Convert.ToInt32(row[2]); actionRow.SequenceTable = sequenceTable; actionRows.Add(actionRow); } actionRows.Sort(); for (int i = 0; i < actionRows.Count && !needAbsoluteScheduling; i++) { WixActionRow actionRow = (WixActionRow)actionRows[i]; WixActionRow standardActionRow = this.standardActions[actionRow.SequenceTable, actionRow.Action]; // create actions for custom actions, dialogs, AppSearch when its moved, and standard actions with non-standard conditions if ("AppSearch" == actionRow.Action || null == standardActionRow || actionRow.Condition != standardActionRow.Condition) { WixActionRow previousActionRow = null; WixActionRow nextActionRow = null; // find the previous action row if there is one if (0 <= i - 1) { previousActionRow = (WixActionRow)actionRows[i - 1]; } // find the next action row if there is one if (actionRows.Count > i + 1) { nextActionRow = (WixActionRow)actionRows[i + 1]; } // the logic for setting the before or after attribute for an action: // 1. If more than one action shares the same sequence number, everything must be absolutely sequenced. // 2. If the next action is a standard action and is 1 sequence number higher, this action occurs before it. // 3. If the previous action is a standard action and is 1 sequence number lower, this action occurs after it. // 4. If this action is not standard and the previous action is 1 sequence number lower and does not occur before this action, this action occurs after it. // 5. If this action is not standard and the previous action does not have the same sequence number and the next action is 1 sequence number higher, this action occurs before it. // 6. If this action is AppSearch and has all standard information, ignore it. // 7. If this action is standard and has a non-standard condition, create the action without any scheduling information. // 8. Everything must be absolutely sequenced. if ((null != previousActionRow && actionRow.Sequence == previousActionRow.Sequence) || (null != nextActionRow && actionRow.Sequence == nextActionRow.Sequence)) { needAbsoluteScheduling = true; } else if (null != nextActionRow && null != this.standardActions[sequenceTable, nextActionRow.Action] && actionRow.Sequence + 1 == nextActionRow.Sequence) { actionRow.Before = nextActionRow.Action; } else if (null != previousActionRow && null != this.standardActions[sequenceTable, previousActionRow.Action] && actionRow.Sequence - 1 == previousActionRow.Sequence) { actionRow.After = previousActionRow.Action; } else if (null == standardActionRow && null != previousActionRow && actionRow.Sequence - 1 == previousActionRow.Sequence && previousActionRow.Before != actionRow.Action) { actionRow.After = previousActionRow.Action; } else if (null == standardActionRow && null != previousActionRow && actionRow.Sequence != previousActionRow.Sequence && null != nextActionRow && actionRow.Sequence + 1 == nextActionRow.Sequence) { actionRow.Before = nextActionRow.Action; } else if ("AppSearch" == actionRow.Action && null != standardActionRow && actionRow.Sequence == standardActionRow.Sequence && actionRow.Condition == standardActionRow.Condition) { // ignore an AppSearch row which has the WiX standard sequence and a standard condition } else if (null != standardActionRow && actionRow.Condition != standardActionRow.Condition) // standard actions get their standard sequence numbers { nonSequencedActionRows.Add(actionRow); } else if (0 < actionRow.Sequence) { needAbsoluteScheduling = true; } } else { suppressedRelativeActionRows.Add(actionRow); } } // create the actions now that we know if they must be absolutely or relatively scheduled foreach (WixActionRow actionRow in actionRows) { if (needAbsoluteScheduling) { // remove any before/after information to ensure this is absolutely sequenced actionRow.Before = null; actionRow.After = null; } else if (nonSequencedActionRows.Contains(actionRow.SequenceTable, actionRow.Action)) { // clear the sequence attribute to ensure this action is scheduled without a sequence number (or before/after) actionRow.Sequence = 0; } else if (suppressedRelativeActionRows.Contains(actionRow.SequenceTable, actionRow.Action)) { // skip the suppressed relatively scheduled action rows continue; } // create the action element this.CreateActionElement(actionRow); } } } } else if (OutputType.Module == this.outputType || this.treatProductAsModule) // finalize the Module sequence tables { foreach (SequenceTable sequenceTable in Enum.GetValues(typeof(SequenceTable))) { // if suppressing UI elements, skip UI-related sequence tables if (this.suppressUI && ("AdminUISequence" == sequenceTable.ToString() || "InstallUISequence" == sequenceTable.ToString())) { continue; } Table actionsTable = new Table(null, this.tableDefinitions["WixAction"]); Table table = tables[String.Concat("Module", sequenceTable.ToString())]; if (null != table) { foreach (Row row in table.Rows) { WixActionRow actionRow = (WixActionRow)actionsTable.CreateRow(null); actionRow.Action = Convert.ToString(row[0]); if (null != row[1]) { actionRow.Sequence = Convert.ToInt32(row[1]); } if (null != row[2] && null != row[3]) { switch (Convert.ToInt32(row[3])) { case 0: actionRow.Before = Convert.ToString(row[2]); break; case 1: actionRow.After = Convert.ToString(row[2]); break; default: this.core.OnMessage(WixWarnings.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[3].Column.Name, row[3])); break; } } if (null != row[4]) { actionRow.Condition = Convert.ToString(row[4]); } actionRow.SequenceTable = sequenceTable; // create action elements for non-standard actions if (null == this.standardActions[actionRow.SequenceTable, actionRow.Action] || null != actionRow.After || null != actionRow.Before) { this.CreateActionElement(actionRow); } } } } } }
/// <summary> /// Finalize the Dialog table. /// </summary> /// <param name="tables">The collection of all tables.</param> /// <remarks> /// Sets the first, default, and cancel control for each dialog and adds all child control /// elements to the dialog. /// </remarks> private void FinalizeDialogTable(TableCollection tables) { // if the user has requested to suppress the UI elements, we have nothing to do if (this.suppressUI) { return; } Table controlTable = tables["Control"]; Table dialogTable = tables["Dialog"]; Hashtable addedControls = new Hashtable(); Hashtable controlRows = new Hashtable(); // index the rows in the control rows (because we need the Control_Next value) if (null != controlTable) { foreach (Row row in controlTable.Rows) { controlRows.Add(row.GetPrimaryKey(DecompilerCore.PrimaryKeyDelimiter), row); } } if (null != dialogTable) { foreach (Row row in dialogTable.Rows) { Wix.Dialog dialog = (Wix.Dialog)this.core.GetIndexedElement(row); string dialogId = Convert.ToString(row[0]); Wix.Control control = (Wix.Control)this.core.GetIndexedElement("Control", dialogId, Convert.ToString(row[7])); if (null == control) { this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, "Dialog", row.GetPrimaryKey(DecompilerCore.PrimaryKeyDelimiter), "Dialog", dialogId, "Control_First", Convert.ToString(row[7]), "Control")); } // add tabbable controls while (null != control) { Row controlRow = (Row)controlRows[String.Concat(dialogId, DecompilerCore.PrimaryKeyDelimiter, control.Id)]; control.TabSkip = Wix.YesNoType.no; dialog.AddChild(control); addedControls.Add(control, null); if (null != controlRow[10]) { control = (Wix.Control)this.core.GetIndexedElement("Control", dialogId, Convert.ToString(controlRow[10])); if (null != control) { // looped back to the first control in the dialog if (addedControls.Contains(control)) { control = null; } } else { this.core.OnMessage(WixWarnings.ExpectedForeignRow(controlRow.SourceLineNumbers, "Control", controlRow.GetPrimaryKey(DecompilerCore.PrimaryKeyDelimiter), "Dialog_", dialogId, "Control_Next", Convert.ToString(controlRow[10]), "Control")); } } else { control = null; } } // set default control if (null != row[8]) { Wix.Control defaultControl = (Wix.Control)this.core.GetIndexedElement("Control", dialogId, Convert.ToString(row[8])); if (null != defaultControl) { defaultControl.Default = Wix.YesNoType.yes; } else { this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, "Dialog", row.GetPrimaryKey(DecompilerCore.PrimaryKeyDelimiter), "Dialog", dialogId, "Control_Default", Convert.ToString(row[8]), "Control")); } } // set cancel control if (null != row[9]) { Wix.Control cancelControl = (Wix.Control)this.core.GetIndexedElement("Control", dialogId, Convert.ToString(row[9])); if (null != cancelControl) { cancelControl.Cancel = Wix.YesNoType.yes; } else { this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, "Dialog", row.GetPrimaryKey(DecompilerCore.PrimaryKeyDelimiter), "Dialog", dialogId, "Control_Cancel", Convert.ToString(row[9]), "Control")); } } } } // add the non-tabbable controls to the dialog if (null != controlTable) { foreach (Row row in controlTable.Rows) { Wix.Control control = (Wix.Control)this.core.GetIndexedElement(row); Wix.Dialog dialog = (Wix.Dialog)this.core.GetIndexedElement("Dialog", Convert.ToString(row[0])); if (null == dialog) { this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, "Control", row.GetPrimaryKey(DecompilerCore.PrimaryKeyDelimiter), "Dialog_", Convert.ToString(row[0]), "Dialog")); continue; } if (!addedControls.Contains(control)) { control.TabSkip = Wix.YesNoType.yes; dialog.AddChild(control); } } } }
/// <summary> /// Finalize the Verb table. /// </summary> /// <param name="tables">The collection of all tables.</param> /// <remarks> /// The Extension table is a foreign table for the Verb table, but the /// foreign key is only part of the primary key of the Extension table, /// so it needs special logic to be nested properly. /// </remarks> private void FinalizeVerbTable(TableCollection tables) { Table extensionTable = tables["Extension"]; Table verbTable = tables["Verb"]; Hashtable extensionElements = new Hashtable(); if (null != extensionTable) { foreach (Row row in extensionTable.Rows) { Wix.Extension extension = (Wix.Extension)this.core.GetIndexedElement(row); if (!extensionElements.Contains(row[0])) { extensionElements.Add(row[0], new ArrayList()); } ((ArrayList)extensionElements[row[0]]).Add(extension); } } if (null != verbTable) { foreach (Row row in verbTable.Rows) { Wix.Verb verb = (Wix.Verb)this.core.GetIndexedElement(row); ArrayList extensionsArray = (ArrayList)extensionElements[row[0]]; if (null != extensionsArray) { foreach (Wix.Extension extension in extensionsArray) { extension.AddChild(verb); } } else { this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, verbTable.Name, row.GetPrimaryKey(DecompilerCore.PrimaryKeyDelimiter), "Extension_", Convert.ToString(row[0]), "Extension")); } } } }
/// <summary> /// Finalize the DuplicateFile and MoveFile tables. /// </summary> /// <param name="tables">The collection of all tables.</param> /// <remarks> /// Sets the source/destination property/directory for each DuplicateFile or /// MoveFile row. /// </remarks> private void FinalizeDuplicateMoveFileTables(TableCollection tables) { Table duplicateFileTable = tables["DuplicateFile"]; Table moveFileTable = tables["MoveFile"]; if (null != duplicateFileTable) { foreach (Row row in duplicateFileTable.Rows) { Wix.CopyFile copyFile = (Wix.CopyFile)this.core.GetIndexedElement(row); if (null != row[4]) { if (null != this.core.GetIndexedElement("Directory", Convert.ToString(row[4]))) { copyFile.DestinationDirectory = Convert.ToString(row[4]); } else { copyFile.DestinationProperty = Convert.ToString(row[4]); } } } } if (null != moveFileTable) { foreach (Row row in moveFileTable.Rows) { Wix.CopyFile copyFile = (Wix.CopyFile)this.core.GetIndexedElement(row); if (null != row[4]) { if (null != this.core.GetIndexedElement("Directory", Convert.ToString(row[4]))) { copyFile.SourceDirectory = Convert.ToString(row[4]); } else { copyFile.SourceProperty = Convert.ToString(row[4]); } } if (null != this.core.GetIndexedElement("Directory", Convert.ToString(row[5]))) { copyFile.DestinationDirectory = Convert.ToString(row[5]); } else { copyFile.DestinationProperty = Convert.ToString(row[5]); } } } }
/// <summary> /// Finalize decompilation. /// </summary> /// <param name="tables">The collection of all tables.</param> private void FinalizeDecompile(TableCollection tables) { if (OutputType.PatchCreation == this.outputType) { this.FinalizeFamilyFileRangesTable(tables); } else { this.FinalizeCheckBoxTable(tables); this.FinalizeComponentTable(tables); this.FinalizeDialogTable(tables); this.FinalizeDuplicateMoveFileTables(tables); this.FinalizeFeatureComponentsTable(tables); this.FinalizeFileTable(tables); this.FinalizeMIMETable(tables); this.FinalizeMsiLockPermissionsExTable(tables); this.FinalizeLockPermissionsTable(tables); this.FinalizeProgIdTable(tables); this.FinalizePropertyTable(tables); this.FinalizeRemoveFileTable(tables); this.FinalizeSearchTables(tables); this.FinalizeUpgradeTable(tables); this.FinalizeSequenceTables(tables); this.FinalizeVerbTable(tables); } }
/// <summary> /// Finalize the FamilyFileRanges table. /// </summary> /// <param name="tables">The collection of all tables.</param> private void FinalizeFamilyFileRangesTable(TableCollection tables) { Table externalFilesTable = tables["ExternalFiles"]; Table familyFileRangesTable = tables["FamilyFileRanges"]; Table targetFiles_OptionalDataTable = tables["TargetFiles_OptionalData"]; Hashtable usedProtectRanges = new Hashtable(); if (null != familyFileRangesTable) { foreach (Row row in familyFileRangesTable.Rows) { Wix.ProtectRange protectRange = new Wix.ProtectRange(); if (null != row[2] && null != row[3]) { string[] retainOffsets = (Convert.ToString(row[2])).Split(','); string[] retainLengths = (Convert.ToString(row[3])).Split(','); if (retainOffsets.Length == retainLengths.Length) { for (int i = 0; i < retainOffsets.Length; i++) { if (retainOffsets[i].StartsWith("0x", StringComparison.Ordinal)) { protectRange.Offset = Convert.ToInt32(retainOffsets[i].Substring(2), 16); } else { protectRange.Offset = Convert.ToInt32(retainOffsets[i], CultureInfo.InvariantCulture); } if (retainLengths[i].StartsWith("0x", StringComparison.Ordinal)) { protectRange.Length = Convert.ToInt32(retainLengths[i].Substring(2), 16); } else { protectRange.Length = Convert.ToInt32(retainLengths[i], CultureInfo.InvariantCulture); } } } else { // TODO: warn } } else if (null != row[2] || null != row[3]) { // TODO: warn about mismatch between columns } this.core.IndexElement(row, protectRange); } } if (null != externalFilesTable) { foreach (Row row in externalFilesTable.Rows) { Wix.ExternalFile externalFile = (Wix.ExternalFile)this.core.GetIndexedElement(row); Wix.ProtectRange protectRange = (Wix.ProtectRange)this.core.GetIndexedElement("FamilyFileRanges", Convert.ToString(row[0]), Convert.ToString(row[1])); if (null != protectRange) { externalFile.AddChild(protectRange); usedProtectRanges[protectRange] = null; } } } if (null != targetFiles_OptionalDataTable) { Table targetImagesTable = tables["TargetImages"]; Table upgradedImagesTable = tables["UpgradedImages"]; Hashtable targetImageRows = new Hashtable(); Hashtable upgradedImagesRows = new Hashtable(); // index the TargetImages table if (null != targetImagesTable) { foreach (Row row in targetImagesTable.Rows) { targetImageRows.Add(row[0], row); } } // index the UpgradedImages table if (null != upgradedImagesTable) { foreach (Row row in upgradedImagesTable.Rows) { upgradedImagesRows.Add(row[0], row); } } foreach (Row row in targetFiles_OptionalDataTable.Rows) { Wix.TargetFile targetFile = (Wix.TargetFile)this.patchTargetFiles[row.GetPrimaryKey(DecompilerCore.PrimaryKeyDelimiter)]; Row targetImageRow = (Row)targetImageRows[row[0]]; if (null == targetImageRow) { this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, targetFiles_OptionalDataTable.Name, row.GetPrimaryKey(DecompilerCore.PrimaryKeyDelimiter), "Target", Convert.ToString(row[0]), "TargetImages")); continue; } Row upgradedImagesRow = (Row)upgradedImagesRows[targetImageRow[3]]; if (null == upgradedImagesRow) { this.core.OnMessage(WixWarnings.ExpectedForeignRow(targetImageRow.SourceLineNumbers, targetImageRow.Table.Name, targetImageRow.GetPrimaryKey(DecompilerCore.PrimaryKeyDelimiter), "Upgraded", Convert.ToString(row[3]), "UpgradedImages")); continue; } Wix.ProtectRange protectRange = (Wix.ProtectRange)this.core.GetIndexedElement("FamilyFileRanges", Convert.ToString(upgradedImagesRow[4]), Convert.ToString(row[1])); if (null != protectRange) { targetFile.AddChild(protectRange); usedProtectRanges[protectRange] = null; } } } if (null != familyFileRangesTable) { foreach (Row row in familyFileRangesTable.Rows) { Wix.ProtectRange protectRange = (Wix.ProtectRange)this.core.GetIndexedElement(row); if (!usedProtectRanges.Contains(protectRange)) { Wix.ProtectFile protectFile = new Wix.ProtectFile(); protectFile.File = Convert.ToString(row[1]); protectFile.AddChild(protectRange); Wix.Family family = (Wix.Family)this.core.GetIndexedElement("ImageFamilies", Convert.ToString(row[0])); if (null != family) { family.AddChild(protectFile); } else { this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, familyFileRangesTable.Name, row.GetPrimaryKey(DecompilerCore.PrimaryKeyDelimiter), "Family", Convert.ToString(row[0]), "ImageFamilies")); } } } } }
/// <summary> /// Finalize the CheckBox table. /// </summary> /// <param name="tables">The collection of all tables.</param> /// <remarks> /// Enumerates through all the Control rows, looking for controls of type "CheckBox" with /// a value in the Property column. This is then possibly matched up with a CheckBox row /// to retrieve a CheckBoxValue. There is no foreign key from the Control to CheckBox table. /// </remarks> private void FinalizeCheckBoxTable(TableCollection tables) { // if the user has requested to suppress the UI elements, we have nothing to do if (this.suppressUI) { return; } Table checkBoxTable = tables["CheckBox"]; Table controlTable = tables["Control"]; Hashtable checkBoxes = new Hashtable(); Hashtable checkBoxProperties = new Hashtable(); // index the CheckBox table if (null != checkBoxTable) { foreach (Row row in checkBoxTable.Rows) { checkBoxes.Add(row.GetPrimaryKey(DecompilerCore.PrimaryKeyDelimiter), row); checkBoxProperties.Add(row.GetPrimaryKey(DecompilerCore.PrimaryKeyDelimiter), false); } } // enumerate through the Control table, adding CheckBox values where appropriate if (null != controlTable) { foreach (Row row in controlTable.Rows) { Wix.Control control = (Wix.Control)this.core.GetIndexedElement(row); if ("CheckBox" == Convert.ToString(row[2]) && null != row[8]) { Row checkBoxRow = (Row)checkBoxes[row[8]]; if (null == checkBoxRow) { this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, "Control", row.GetPrimaryKey(DecompilerCore.PrimaryKeyDelimiter), "Property", Convert.ToString(row[8]), "CheckBox")); } else { // if we've seen this property already, create a reference to it if (Convert.ToBoolean(checkBoxProperties[row[8]])) { control.CheckBoxPropertyRef = Convert.ToString(row[8]); } else { control.Property = Convert.ToString(row[8]); checkBoxProperties[row[8]] = true; } if (null != checkBoxRow[1]) { control.CheckBoxValue = Convert.ToString(checkBoxRow[1]); } } } } } }
/// <summary> /// Finalize the FeatureComponents table. /// </summary> /// <param name="tables">The collection of all tables.</param> /// <remarks> /// Since tables specifying references to the FeatureComponents table have references to /// the Feature and Component table separately, but not the FeatureComponents table specifically, /// the FeatureComponents table and primary features must be decompiled during finalization. /// </remarks> private void FinalizeFeatureComponentsTable(TableCollection tables) { Table classTable = tables["Class"]; Table extensionTable = tables["Extension"]; Table msiAssemblyTable = tables["MsiAssembly"]; Table publishComponentTable = tables["PublishComponent"]; Table shortcutTable = tables["Shortcut"]; Table typeLibTable = tables["TypeLib"]; if (null != classTable) { foreach (Row row in classTable.Rows) { this.SetPrimaryFeature(row, 11, 2); } } if (null != extensionTable) { foreach (Row row in extensionTable.Rows) { this.SetPrimaryFeature(row, 4, 1); } } if (null != msiAssemblyTable) { foreach (Row row in msiAssemblyTable.Rows) { this.SetPrimaryFeature(row, 1, 0); } } if (null != publishComponentTable) { foreach (Row row in publishComponentTable.Rows) { this.SetPrimaryFeature(row, 4, 2); } } if (null != shortcutTable) { foreach (Row row in shortcutTable.Rows) { string target = Convert.ToString(row[4]); if (!target.StartsWith("[", StringComparison.Ordinal) && !target.EndsWith("]", StringComparison.Ordinal)) { this.SetPrimaryFeature(row, 4, 3); } } } if (null != typeLibTable) { foreach (Row row in typeLibTable.Rows) { this.SetPrimaryFeature(row, 6, 2); } } }