aboutsummaryrefslogtreecommitdiff
path: root/src/WixToolset.Core/Linker.cs
diff options
context:
space:
mode:
authorRob Mensching <rob@firegiant.com>2017-12-30 17:09:15 -0800
committerRob Mensching <rob@firegiant.com>2017-12-30 17:09:15 -0800
commitc5190ae74ab8fe13609362efce88fa4b8cc24f34 (patch)
treee7762224afad491c37b70bab13756552c72fdd26 /src/WixToolset.Core/Linker.cs
parentd4f73e72985dc2f36e4228358f4dc9b6114414ab (diff)
downloadwix-c5190ae74ab8fe13609362efce88fa4b8cc24f34.tar.gz
wix-c5190ae74ab8fe13609362efce88fa4b8cc24f34.tar.bz2
wix-c5190ae74ab8fe13609362efce88fa4b8cc24f34.zip
Fix resolution of localizations that are embedded in intermediates
Diffstat (limited to 'src/WixToolset.Core/Linker.cs')
-rw-r--r--src/WixToolset.Core/Linker.cs420
1 files changed, 220 insertions, 200 deletions
diff --git a/src/WixToolset.Core/Linker.cs b/src/WixToolset.Core/Linker.cs
index 79ddd30a..db2514fb 100644
--- a/src/WixToolset.Core/Linker.cs
+++ b/src/WixToolset.Core/Linker.cs
@@ -32,9 +32,6 @@ namespace WixToolset.Core
32 { 32 {
33 this.ServiceProvider = serviceProvider; 33 this.ServiceProvider = serviceProvider;
34 this.sectionIdOnRows = true; // TODO: what is the correct value for this? 34 this.sectionIdOnRows = true; // TODO: what is the correct value for this?
35
36 //this.extensionData = new List<IExtensionData>();
37 //this.inspectorExtensions = new List<InspectorExtension>();
38 } 35 }
39 36
40 private IServiceProvider ServiceProvider { get; } 37 private IServiceProvider ServiceProvider { get; }
@@ -78,40 +75,49 @@ namespace WixToolset.Core
78 this.Context.Extensions = extensionManager.Create<ILinkerExtension>(); 75 this.Context.Extensions = extensionManager.Create<ILinkerExtension>();
79 this.Context.ExtensionData = extensionManager.Create<IExtensionData>(); 76 this.Context.ExtensionData = extensionManager.Create<IExtensionData>();
80 this.Context.ExpectedOutputType = this.OutputType; 77 this.Context.ExpectedOutputType = this.OutputType;
81 this.Context.Intermediates = this.Intermediates.Union(this.Libraries).ToList(); 78 this.Context.Intermediates = this.Intermediates.Concat(this.Libraries).ToList();
82 this.Context.TupleDefinitionCreator = creator; 79 this.Context.TupleDefinitionCreator = creator;
83 80
84 var sections = this.Context.Intermediates.SelectMany(i => i.Sections).ToList(); 81 foreach (var extension in this.Context.Extensions)
82 {
83 extension.PreLink(this.Context);
84 }
85 85
86 // Add sections from the extensions with data. 86 Intermediate intermediate = null;
87 foreach (var data in this.Context.ExtensionData) 87 try
88 { 88 {
89 var library = data.GetLibrary(this.Context.TupleDefinitionCreator); 89 var sections = this.Context.Intermediates.SelectMany(i => i.Sections).ToList();
90 var localizations = this.Context.Intermediates.SelectMany(i => i.Localizations).ToList();
90 91
91 if (library != null) 92 // Add sections from the extensions with data.
93 foreach (var data in this.Context.ExtensionData)
92 { 94 {
93 sections.AddRange(library.Sections); 95 var library = data.GetLibrary(this.Context.TupleDefinitionCreator);
96
97 if (library != null)
98 {
99 sections.AddRange(library.Sections);
100 }
94 } 101 }
95 }
96 102
97#if MOVE_TO_BACKEND 103#if MOVE_TO_BACKEND
98 bool containsModuleSubstitution = false; 104 bool containsModuleSubstitution = false;
99 bool containsModuleConfiguration = false; 105 bool containsModuleConfiguration = false;
100#endif 106#endif
101 107
102 //this.activeOutput = null; 108 //this.activeOutput = null;
103 109
104 //TableDefinitionCollection customTableDefinitions = new TableDefinitionCollection(); 110 //TableDefinitionCollection customTableDefinitions = new TableDefinitionCollection();
105 //IntermediateTuple customRows = new List<IntermediateTuple>(); 111 //IntermediateTuple customRows = new List<IntermediateTuple>();
106 112
107#if MOVE_TO_BACKEND 113#if MOVE_TO_BACKEND
108 StringCollection generatedShortFileNameIdentifiers = new StringCollection(); 114 StringCollection generatedShortFileNameIdentifiers = new StringCollection();
109 Hashtable generatedShortFileNames = new Hashtable(); 115 Hashtable generatedShortFileNames = new Hashtable();
110#endif 116#endif
111 117
112 Hashtable multipleFeatureComponents = new Hashtable(); 118 Hashtable multipleFeatureComponents = new Hashtable();
113 119
114 var wixVariables = new Dictionary<string, WixVariableTuple>(); 120 var wixVariables = new Dictionary<string, WixVariableTuple>();
115 121
116#if MOVE_TO_BACKEND 122#if MOVE_TO_BACKEND
117 // verify that modularization types match for foreign key relationships 123 // verify that modularization types match for foreign key relationships
@@ -143,114 +149,117 @@ namespace WixToolset.Core
143 } 149 }
144#endif 150#endif
145 151
146 // First find the entry section and while processing all sections load all the symbols from all of the sections. 152 // First find the entry section and while processing all sections load all the symbols from all of the sections.
147 // sections.FindEntrySectionAndLoadSymbols(false, this, expectedOutputType, out entrySection, out allSymbols); 153 // sections.FindEntrySectionAndLoadSymbols(false, this, expectedOutputType, out entrySection, out allSymbols);
148 var find = new FindEntrySectionAndLoadSymbolsCommand(this.Context.Messaging, sections); 154 var find = new FindEntrySectionAndLoadSymbolsCommand(this.Context.Messaging, sections);
149 find.ExpectedOutputType = this.Context.ExpectedOutputType; 155 find.ExpectedOutputType = this.Context.ExpectedOutputType;
150 find.Execute(); 156 find.Execute();
151 157
152 // Must have found the entry section by now. 158 // Must have found the entry section by now.
153 if (null == find.EntrySection) 159 if (null == find.EntrySection)
154 { 160 {
155 throw new WixException(ErrorMessages.MissingEntrySection(this.Context.ExpectedOutputType.ToString())); 161 throw new WixException(ErrorMessages.MissingEntrySection(this.Context.ExpectedOutputType.ToString()));
156 } 162 }
157 163
158 // Add the missing standard action symbols. 164 // Add the missing standard action symbols.
159 this.LoadStandardActionSymbols(find.EntrySection, find.Symbols); 165 this.LoadStandardActionSymbols(find.EntrySection, find.Symbols);
160 166
161 // Resolve the symbol references to find the set of sections we care about for linking. 167 // Resolve the symbol references to find the set of sections we care about for linking.
162 // Of course, we start with the entry section (that's how it got its name after all). 168 // Of course, we start with the entry section (that's how it got its name after all).
163 var resolve = new ResolveReferencesCommand(this.Context.Messaging, find.EntrySection, find.Symbols); 169 var resolve = new ResolveReferencesCommand(this.Context.Messaging, find.EntrySection, find.Symbols);
164 resolve.BuildingMergeModule = (SectionType.Module == find.EntrySection.Type); 170 resolve.BuildingMergeModule = (SectionType.Module == find.EntrySection.Type);
165 171
166 resolve.Execute(); 172 resolve.Execute();
167 173
168 if (this.Context.Messaging.EncounteredError) 174 if (this.Context.Messaging.EncounteredError)
169 { 175 {
170 return null; 176 return null;
171 } 177 }
172 178
173 // Reset the sections to only those that were resolved then flatten the complex 179 // Reset the sections to only those that were resolved then flatten the complex
174 // references that particpate in groups. 180 // references that particpate in groups.
175 sections = resolve.ResolvedSections.ToList(); 181 sections = resolve.ResolvedSections.ToList();
176 182
177 this.FlattenSectionsComplexReferences(sections); 183 // TODO: consider filtering "localizations" down to only those localizations from
184 // intermediates in the sections.
178 185
179 if (this.Context.Messaging.EncounteredError) 186 this.FlattenSectionsComplexReferences(sections);
180 {
181 return null;
182 }
183 187
184 // The hard part in linking is processing the complex references. 188 if (this.Context.Messaging.EncounteredError)
185 var referencedComponents = new HashSet<string>(); 189 {
186 var componentsToFeatures = new ConnectToFeatureCollection(); 190 return null;
187 var featuresToFeatures = new ConnectToFeatureCollection(); 191 }
188 var modulesToFeatures = new ConnectToFeatureCollection();
189 this.ProcessComplexReferences(find.EntrySection, sections, referencedComponents, componentsToFeatures, featuresToFeatures, modulesToFeatures);
190 192
191 if (this.Context.Messaging.EncounteredError) 193 // The hard part in linking is processing the complex references.
192 { 194 var referencedComponents = new HashSet<string>();
193 return null; 195 var componentsToFeatures = new ConnectToFeatureCollection();
194 } 196 var featuresToFeatures = new ConnectToFeatureCollection();
197 var modulesToFeatures = new ConnectToFeatureCollection();
198 this.ProcessComplexReferences(find.EntrySection, sections, referencedComponents, componentsToFeatures, featuresToFeatures, modulesToFeatures);
195 199
196 // Display an error message for Components that were not referenced by a Feature. 200 if (this.Context.Messaging.EncounteredError)
197 foreach (var symbol in resolve.ReferencedSymbols.Where(s => s.Row.Definition.Type == TupleDefinitionType.Component))
198 {
199 if (!referencedComponents.Contains(symbol.Name))
200 { 201 {
201 this.OnMessage(ErrorMessages.OrphanedComponent(symbol.Row.SourceLineNumbers, symbol.Row.Id.Id)); 202 return null;
202 } 203 }
203 }
204 204
205 // Report duplicates that would ultimately end up being primary key collisions. 205 // Display an error message for Components that were not referenced by a Feature.
206 var reportDupes = new ReportConflictingSymbolsCommand(this.Context.Messaging, find.PossiblyConflictingSymbols, resolve.ResolvedSections); 206 foreach (var symbol in resolve.ReferencedSymbols.Where(s => s.Row.Definition.Type == TupleDefinitionType.Component))
207 reportDupes.Execute(); 207 {
208 if (!referencedComponents.Contains(symbol.Name))
209 {
210 this.OnMessage(ErrorMessages.OrphanedComponent(symbol.Row.SourceLineNumbers, symbol.Row.Id.Id));
211 }
212 }
208 213
209 if (this.Context.Messaging.EncounteredError) 214 // Report duplicates that would ultimately end up being primary key collisions.
210 { 215 var reportDupes = new ReportConflictingSymbolsCommand(this.Context.Messaging, find.PossiblyConflictingSymbols, resolve.ResolvedSections);
211 return null; 216 reportDupes.Execute();
212 }
213 217
214 // resolve the feature to feature connects 218 if (this.Context.Messaging.EncounteredError)
215 this.ResolveFeatureToFeatureConnects(featuresToFeatures, find.Symbols); 219 {
220 return null;
221 }
216 222
217 // start generating OutputTables and OutputRows for all the sections in the output 223 // resolve the feature to feature connects
218 var ensureTableRows = new List<IntermediateTuple>(); 224 this.ResolveFeatureToFeatureConnects(featuresToFeatures, find.Symbols);
219 225
220 // Create the section to hold the linked content. 226 // start generating OutputTables and OutputRows for all the sections in the output
221 var resolvedSection = new IntermediateSection(find.EntrySection.Id, find.EntrySection.Type, find.EntrySection.Codepage); 227 var ensureTableRows = new List<IntermediateTuple>();
222 228
223 var sectionCount = 0; 229 // Create the section to hold the linked content.
230 var resolvedSection = new IntermediateSection(find.EntrySection.Id, find.EntrySection.Type, find.EntrySection.Codepage);
224 231
225 foreach (var section in sections) 232 var sectionCount = 0;
226 {
227 sectionCount++;
228 233
229 var sectionId = section.Id; 234 foreach (var section in sections)
230 if (null == sectionId && this.sectionIdOnRows)
231 { 235 {
232 sectionId = "wix.section." + sectionCount.ToString(CultureInfo.InvariantCulture); 236 sectionCount++;
233 }
234 237
235 foreach (var tuple in section.Tuples) 238 var sectionId = section.Id;
236 { 239 if (null == sectionId && this.sectionIdOnRows)
237 var copyTuple = true; // by default, copy tuples. 240 {
241 sectionId = "wix.section." + sectionCount.ToString(CultureInfo.InvariantCulture);
242 }
238 243
239 // handle special tables 244 foreach (var tuple in section.Tuples)
240 switch (tuple.Definition.Type)
241 { 245 {
246 var copyTuple = true; // by default, copy tuples.
247
248 // handle special tables
249 switch (tuple.Definition.Type)
250 {
242#if MOVE_TO_BACKEND 251#if MOVE_TO_BACKEND
243 case "AppSearch": 252 case "AppSearch":
244 this.activeOutput.EnsureTable(this.tableDefinitions["Signature"]); 253 this.activeOutput.EnsureTable(this.tableDefinitions["Signature"]);
245 break; 254 break;
246#endif 255#endif
247 256
248 case TupleDefinitionType.Class: 257 case TupleDefinitionType.Class:
249 if (SectionType.Product == resolvedSection.Type) 258 if (SectionType.Product == resolvedSection.Type)
250 { 259 {
251 this.ResolveFeatures(tuple, 2, 11, componentsToFeatures, multipleFeatureComponents); 260 this.ResolveFeatures(tuple, 2, 11, componentsToFeatures, multipleFeatureComponents);
252 } 261 }
253 break; 262 break;
254 263
255#if MOVE_TO_BACKEND 264#if MOVE_TO_BACKEND
256 case "CustomAction": 265 case "CustomAction":
@@ -304,12 +313,12 @@ namespace WixToolset.Core
304 } 313 }
305 break; 314 break;
306#endif 315#endif
307 case TupleDefinitionType.Extension: 316 case TupleDefinitionType.Extension:
308 if (SectionType.Product == resolvedSection.Type) 317 if (SectionType.Product == resolvedSection.Type)
309 { 318 {
310 this.ResolveFeatures(tuple, 1, 4, componentsToFeatures, multipleFeatureComponents); 319 this.ResolveFeatures(tuple, 1, 4, componentsToFeatures, multipleFeatureComponents);
311 } 320 }
312 break; 321 break;
313 322
314#if MOVE_TO_BACKEND 323#if MOVE_TO_BACKEND
315 case TupleDefinitionType.ModuleSubstitution: 324 case TupleDefinitionType.ModuleSubstitution:
@@ -321,12 +330,12 @@ namespace WixToolset.Core
321 break; 330 break;
322#endif 331#endif
323 332
324 case TupleDefinitionType.MsiAssembly: 333 case TupleDefinitionType.MsiAssembly:
325 if (SectionType.Product == resolvedSection.Type) 334 if (SectionType.Product == resolvedSection.Type)
326 { 335 {
327 this.ResolveFeatures(tuple, 0, 1, componentsToFeatures, multipleFeatureComponents); 336 this.ResolveFeatures(tuple, 0, 1, componentsToFeatures, multipleFeatureComponents);
328 } 337 }
329 break; 338 break;
330 339
331#if MOVE_TO_BACKEND 340#if MOVE_TO_BACKEND
332 case "ProgId": 341 case "ProgId":
@@ -348,26 +357,26 @@ namespace WixToolset.Core
348 break; 357 break;
349#endif 358#endif
350 359
351 case TupleDefinitionType.PublishComponent: 360 case TupleDefinitionType.PublishComponent:
352 if (SectionType.Product == resolvedSection.Type) 361 if (SectionType.Product == resolvedSection.Type)
353 { 362 {
354 this.ResolveFeatures(tuple, 2, 4, componentsToFeatures, multipleFeatureComponents); 363 this.ResolveFeatures(tuple, 2, 4, componentsToFeatures, multipleFeatureComponents);
355 } 364 }
356 break; 365 break;
357 366
358 case TupleDefinitionType.Shortcut: 367 case TupleDefinitionType.Shortcut:
359 if (SectionType.Product == resolvedSection.Type) 368 if (SectionType.Product == resolvedSection.Type)
360 { 369 {
361 this.ResolveFeatures(tuple, 3, 4, componentsToFeatures, multipleFeatureComponents); 370 this.ResolveFeatures(tuple, 3, 4, componentsToFeatures, multipleFeatureComponents);
362 } 371 }
363 break; 372 break;
364 373
365 case TupleDefinitionType.TypeLib: 374 case TupleDefinitionType.TypeLib:
366 if (SectionType.Product == resolvedSection.Type) 375 if (SectionType.Product == resolvedSection.Type)
367 { 376 {
368 this.ResolveFeatures(tuple, 2, 6, componentsToFeatures, multipleFeatureComponents); 377 this.ResolveFeatures(tuple, 2, 6, componentsToFeatures, multipleFeatureComponents);
369 } 378 }
370 break; 379 break;
371 380
372#if SOLVE_CUSTOM_TABLE 381#if SOLVE_CUSTOM_TABLE
373 case "WixCustomTable": 382 case "WixCustomTable":
@@ -385,9 +394,9 @@ namespace WixToolset.Core
385 break; 394 break;
386#endif 395#endif
387 396
388 case TupleDefinitionType.WixEnsureTable: 397 case TupleDefinitionType.WixEnsureTable:
389 ensureTableRows.Add(tuple); 398 ensureTableRows.Add(tuple);
390 break; 399 break;
391 400
392 401
393#if MOVE_TO_BACKEND 402#if MOVE_TO_BACKEND
@@ -410,66 +419,66 @@ namespace WixToolset.Core
410 break; 419 break;
411#endif 420#endif
412 421
413 case TupleDefinitionType.WixMerge: 422 case TupleDefinitionType.WixMerge:
414 if (SectionType.Product == resolvedSection.Type) 423 if (SectionType.Product == resolvedSection.Type)
415 { 424 {
416 this.ResolveFeatures(tuple, 0, 7, modulesToFeatures, null); 425 this.ResolveFeatures(tuple, 0, 7, modulesToFeatures, null);
417 } 426 }
418 break; 427 break;
419
420 case TupleDefinitionType.WixComplexReference:
421 copyTuple = false;
422 break;
423 428
424 case TupleDefinitionType.WixSimpleReference: 429 case TupleDefinitionType.WixComplexReference:
425 copyTuple = false; 430 copyTuple = false;
426 break; 431 break;
427 432
428 case TupleDefinitionType.WixVariable: 433 case TupleDefinitionType.WixSimpleReference:
429 // check for colliding values and collect the wix variable rows 434 copyTuple = false;
430 { 435 break;
431 var row = (WixVariableTuple)tuple;
432 436
433 if (wixVariables.TryGetValue(row.WixVariable, out var collidingRow)) 437 case TupleDefinitionType.WixVariable:
438 // check for colliding values and collect the wix variable rows
434 { 439 {
435 if (collidingRow.Overridable && !row.Overridable) 440 var row = (WixVariableTuple)tuple;
441
442 if (wixVariables.TryGetValue(row.WixVariable, out var collidingRow))
436 { 443 {
437 wixVariables[row.WixVariable] = row; 444 if (collidingRow.Overridable && !row.Overridable)
445 {
446 wixVariables[row.WixVariable] = row;
447 }
448 else if (!row.Overridable || (collidingRow.Overridable && row.Overridable))
449 {
450 this.OnMessage(ErrorMessages.WixVariableCollision(row.SourceLineNumbers, row.WixVariable));
451 }
438 } 452 }
439 else if (!row.Overridable || (collidingRow.Overridable && row.Overridable)) 453 else
440 { 454 {
441 this.OnMessage(ErrorMessages.WixVariableCollision(row.SourceLineNumbers, row.WixVariable)); 455 wixVariables.Add(row.WixVariable, row);
442 } 456 }
443 } 457 }
444 else
445 {
446 wixVariables.Add(row.WixVariable, row);
447 }
448 }
449 458
450 copyTuple = false; 459 copyTuple = false;
451 break; 460 break;
452 } 461 }
453 462
454 if (copyTuple) 463 if (copyTuple)
455 { 464 {
456 resolvedSection.Tuples.Add(tuple); 465 resolvedSection.Tuples.Add(tuple);
466 }
457 } 467 }
458 } 468 }
459 }
460 469
461 // copy the module to feature connections into the output 470 // copy the module to feature connections into the output
462 foreach (ConnectToFeature connectToFeature in modulesToFeatures) 471 foreach (ConnectToFeature connectToFeature in modulesToFeatures)
463 {
464 foreach (var feature in connectToFeature.ConnectFeatures)
465 { 472 {
466 var row = new WixFeatureModulesTuple(); 473 foreach (var feature in connectToFeature.ConnectFeatures)
467 row.Feature_ = feature; 474 {
468 row.WixMerge_ = connectToFeature.ChildId; 475 var row = new WixFeatureModulesTuple();
476 row.Feature_ = feature;
477 row.WixMerge_ = connectToFeature.ChildId;
469 478
470 resolvedSection.Tuples.Add(row); 479 resolvedSection.Tuples.Add(row);
480 }
471 } 481 }
472 }
473 482
474#if MOVE_TO_BACKEND 483#if MOVE_TO_BACKEND
475 // ensure the creation of tables that need to exist 484 // ensure the creation of tables that need to exist
@@ -612,24 +621,24 @@ namespace WixToolset.Core
612 } 621 }
613#endif 622#endif
614 623
615 //correct the section Id in FeatureComponents table 624 //correct the section Id in FeatureComponents table
616 if (this.sectionIdOnRows) 625 if (this.sectionIdOnRows)
617 { 626 {
618 //var componentSectionIds = new Dictionary<string, string>(); 627 //var componentSectionIds = new Dictionary<string, string>();
619 628
620 //foreach (var componentTuple in entrySection.Tuples.OfType<ComponentTuple>()) 629 //foreach (var componentTuple in entrySection.Tuples.OfType<ComponentTuple>())
621 //{ 630 //{
622 // componentSectionIds.Add(componentTuple.Id.Id, componentTuple.SectionId); 631 // componentSectionIds.Add(componentTuple.Id.Id, componentTuple.SectionId);
623 //} 632 //}
624 633
625 //foreach (var featureComponentTuple in entrySection.Tuples.OfType<FeatureComponentsTuple>()) 634 //foreach (var featureComponentTuple in entrySection.Tuples.OfType<FeatureComponentsTuple>())
626 //{ 635 //{
627 // if (componentSectionIds.TryGetValue(featureComponentTuple.Component_, out var componentSectionId)) 636 // if (componentSectionIds.TryGetValue(featureComponentTuple.Component_, out var componentSectionId))
628 // { 637 // {
629 // featureComponentTuple.SectionId = componentSectionId; 638 // featureComponentTuple.SectionId = componentSectionId;
630 // } 639 // }
631 //} 640 //}
632 } 641 }
633 642
634#if MOVE_TO_BACKEND 643#if MOVE_TO_BACKEND
635 // add the ModuleSubstitution table to the ModuleIgnoreTable 644 // add the ModuleSubstitution table to the ModuleIgnoreTable
@@ -698,27 +707,38 @@ namespace WixToolset.Core
698 } 707 }
699#endif 708#endif
700 709
701 // copy the wix variable rows to the output after all overriding has been accounted for. 710 // copy the wix variable rows to the output after all overriding has been accounted for.
702 foreach (var row in wixVariables.Values) 711 foreach (var row in wixVariables.Values)
703 { 712 {
704 resolvedSection.Tuples.Add(row); 713 resolvedSection.Tuples.Add(row);
705 } 714 }
706 715
707 // Bundles have groups of data that must be flattened in a way different from other types. 716 // Bundles have groups of data that must be flattened in a way different from other types.
708 this.FlattenBundleTables(resolvedSection); 717 this.FlattenBundleTables(resolvedSection);
709 718
710 if (this.Context.Messaging.EncounteredError) 719 if (this.Context.Messaging.EncounteredError)
711 { 720 {
712 return null; 721 return null;
713 } 722 }
714 723
715 var output = new Intermediate(resolvedSection.Id, new[] { resolvedSection }, null, null); 724 var collate = new CollateLocalizationsCommand(this.Context.Messaging, localizations);
725 var localizationsByCulture = collate.Execute();
726
727 intermediate = new Intermediate(resolvedSection.Id, new[] { resolvedSection }, localizationsByCulture, null);
716 728
717#if MOVE_TO_BACKEND 729#if MOVE_TO_BACKEND
718 this.CheckOutputConsistency(output); 730 this.CheckOutputConsistency(output);
719#endif 731#endif
732 }
733 finally
734 {
735 foreach (var extension in this.Context.Extensions)
736 {
737 extension.PostLink(intermediate);
738 }
739 }
720 740
721 return this.Context.Messaging.EncounteredError ? null : output; 741 return this.Context.Messaging.EncounteredError ? null : intermediate;
722 } 742 }
723 743
724#if SOLVE_CUSTOM_TABLE 744#if SOLVE_CUSTOM_TABLE