Merge pull request #3522 from henricm/fix-csharp-compiler-path-windows
[mono.git] / mcs / class / referencesource / mscorlib / system / resources / manifestbasedresourcegroveler.cs
1 // ==++==
2 // 
3 //   Copyright (c) Microsoft Corporation.  All rights reserved.
4 // 
5 // ==--==
6 /*============================================================
7 **
8 ** Class:  ManifestBasedResourceGroveler
9 ** 
10 ** <OWNER>[....]</OWNER>
11 **
12 **
13 ** Purpose: Searches for resources in Assembly manifest, used
14 ** for assembly-based resource lookup.
15 **
16 ** 
17 ===========================================================*/
18 namespace System.Resources {
19
20     using System;
21     using System.Collections;
22     using System.Collections.Generic;
23     using System.Globalization;
24     using System.IO;
25     using System.Reflection;
26     using System.Runtime.InteropServices;
27     using System.Runtime.CompilerServices;
28     using System.Runtime.Versioning;
29     using System.Text;
30     using System.Threading;
31     using System.Diagnostics.Contracts;
32     using Microsoft.Win32;
33
34 #if !FEATURE_CORECLR
35     using System.Diagnostics.Tracing;
36 #endif
37
38     //
39     // Note: this type is integral to the construction of exception objects,
40     // and sometimes this has to be done in low memory situtations (OOM) or
41     // to create TypeInitializationExceptions due to failure of a static class
42     // constructor. This type needs to be extremely careful and assume that 
43     // any type it references may have previously failed to construct, so statics
44     // belonging to that type may not be initialized. FrameworkEventSource.Log
45     // is one such example.
46     //
47     internal class ManifestBasedResourceGroveler : IResourceGroveler
48     {
49
50         private ResourceManager.ResourceManagerMediator _mediator;
51
52         public ManifestBasedResourceGroveler(ResourceManager.ResourceManagerMediator mediator)
53         {
54             // here and below: convert asserts to preconditions where appropriate when we get
55             // contracts story in place.
56             Contract.Requires(mediator != null, "mediator shouldn't be null; check caller");
57             _mediator = mediator;
58         }
59
60         [System.Security.SecuritySafeCritical]
61         [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
62         public ResourceSet GrovelForResourceSet(CultureInfo culture, Dictionary<String, ResourceSet> localResourceSets, bool tryParents, bool createIfNotExists, ref StackCrawlMark stackMark)
63         {
64             Contract.Assert(culture != null, "culture shouldn't be null; check caller");
65             Contract.Assert(localResourceSets != null, "localResourceSets shouldn't be null; check caller");
66
67             ResourceSet rs = null;
68             Stream stream = null;
69             RuntimeAssembly satellite = null;
70
71             // 1. Fixups for ultimate fallbacks
72             CultureInfo lookForCulture = UltimateFallbackFixup(culture);
73
74             // 2. Look for satellite assembly or main assembly, as appropriate
75             if (lookForCulture.HasInvariantCultureName && _mediator.FallbackLoc == UltimateResourceFallbackLocation.MainAssembly)
76             {
77                 // don't bother looking in satellites in this case
78                 satellite = _mediator.MainAssembly;
79             }
80 #if RESOURCE_SATELLITE_CONFIG
81             // If our config file says the satellite isn't here, don't ask for it.
82             else if (!lookForCulture.HasInvariantCultureName && !_mediator.TryLookingForSatellite(lookForCulture))
83             {
84                 satellite = null;
85             }
86 #endif
87             else
88             {
89                 satellite = GetSatelliteAssembly(lookForCulture, ref stackMark);
90
91                 if (satellite == null)
92                 {
93                     bool raiseException = (culture.HasInvariantCultureName && (_mediator.FallbackLoc == UltimateResourceFallbackLocation.Satellite));
94                     // didn't find satellite, give error if necessary
95                     if (raiseException)
96                     {
97                         HandleSatelliteMissing();
98                     }
99                 }
100             }
101
102             // get resource file name we'll search for. Note, be careful if you're moving this statement
103             // around because lookForCulture may be modified from originally requested culture above.
104             String fileName = _mediator.GetResourceFileName(lookForCulture);
105
106             // 3. If we identified an assembly to search; look in manifest resource stream for resource file
107             if (satellite != null)
108             {
109                 // Handle case in here where someone added a callback for assembly load events.
110                 // While no other threads have called into GetResourceSet, our own thread can!
111                 // At that point, we could already have an RS in our hash table, and we don't 
112                 // want to add it twice.
113                 lock (localResourceSets)
114                 {
115                     if (localResourceSets.TryGetValue(culture.Name, out rs))
116                     {
117 #if !FEATURE_CORECLR && !MONO
118                         if (FrameworkEventSource.IsInitialized)
119                         {
120                             FrameworkEventSource.Log.ResourceManagerFoundResourceSetInCacheUnexpected(_mediator.BaseName, _mediator.MainAssembly, culture.Name);
121                         }
122 #endif
123                     }
124                 }
125
126                 stream = GetManifestResourceStream(satellite, fileName, ref stackMark);
127             }
128
129 #if !FEATURE_CORECLR && !MONO
130             if (FrameworkEventSource.IsInitialized)
131             {
132                 if (stream != null)
133                 {
134                     FrameworkEventSource.Log.ResourceManagerStreamFound(_mediator.BaseName, _mediator.MainAssembly, culture.Name, satellite, fileName);
135                 }
136                 else
137                 {
138                     FrameworkEventSource.Log.ResourceManagerStreamNotFound(_mediator.BaseName, _mediator.MainAssembly, culture.Name, satellite, fileName);
139                 }
140             }
141 #endif
142
143             // 4a. Found a stream; create a ResourceSet if possible
144             if (createIfNotExists && stream != null && rs == null)
145             {
146 #if !FEATURE_CORECLR && !MONO
147                 if (FrameworkEventSource.IsInitialized)
148                 {
149                     FrameworkEventSource.Log.ResourceManagerCreatingResourceSet(_mediator.BaseName, _mediator.MainAssembly, culture.Name, fileName);
150                 }
151 #endif
152                 rs = CreateResourceSet(stream, satellite);
153             }
154             else if (stream == null && tryParents)
155             {
156                 // 4b. Didn't find stream; give error if necessary
157                 bool raiseException = culture.HasInvariantCultureName;
158                 if (raiseException)
159                 {
160                     HandleResourceStreamMissing(fileName);
161                 }
162             }
163
164 #if !FEATURE_CORECLR && !MONO
165             if (!createIfNotExists && stream != null && rs == null) 
166             {
167                 if (FrameworkEventSource.IsInitialized)
168                 {
169                     FrameworkEventSource.Log.ResourceManagerNotCreatingResourceSet(_mediator.BaseName, _mediator.MainAssembly, culture.Name);
170                 }
171             }
172 #endif
173
174             return rs;
175         }
176
177 #if !FEATURE_CORECLR
178         // Returns whether or not the main assembly contains a particular resource
179         // file in it's assembly manifest.  Used to verify that the neutral 
180         // Culture's .resources file is present in the main assembly
181         public bool HasNeutralResources(CultureInfo culture, String defaultResName)
182         {
183             String resName = defaultResName;
184             if (_mediator.LocationInfo != null && _mediator.LocationInfo.Namespace != null)
185                 resName = _mediator.LocationInfo.Namespace + Type.Delimiter + defaultResName;
186             String[] resourceFiles = _mediator.MainAssembly.GetManifestResourceNames();
187             foreach(String s in resourceFiles)
188                 if (s.Equals(resName))
189                     return true;
190             return false;
191         }
192 #endif
193
194         private CultureInfo UltimateFallbackFixup(CultureInfo lookForCulture)
195         {
196
197             CultureInfo returnCulture = lookForCulture;
198
199             // If our neutral resources were written in this culture AND we know the main assembly
200             // does NOT contain neutral resources, don't probe for this satellite.
201             if (lookForCulture.Name == _mediator.NeutralResourcesCulture.Name &&
202                 _mediator.FallbackLoc == UltimateResourceFallbackLocation.MainAssembly)
203             {
204 #if !FEATURE_CORECLR && !MONO
205                 if (FrameworkEventSource.IsInitialized)
206                 {
207                     FrameworkEventSource.Log.ResourceManagerNeutralResourcesSufficient(_mediator.BaseName, _mediator.MainAssembly, lookForCulture.Name);
208                 }
209 #endif
210
211                 returnCulture = CultureInfo.InvariantCulture;
212             }
213             else if (lookForCulture.HasInvariantCultureName && _mediator.FallbackLoc == UltimateResourceFallbackLocation.Satellite)
214             {
215                 returnCulture = _mediator.NeutralResourcesCulture;
216             }
217
218             return returnCulture;
219
220         }
221
222         [System.Security.SecurityCritical]
223         internal static CultureInfo GetNeutralResourcesLanguage(Assembly a, ref UltimateResourceFallbackLocation fallbackLocation)
224         {
225
226 #if FEATURE_LEGACYNETCF
227             // Windows Phone 7.0/7.1 ignore NeutralResourceLanguage attribute and 
228             // defaults fallbackLocation to MainAssembly
229             if (CompatibilitySwitches.IsAppEarlierThanWindowsPhone8)
230             {
231                 fallbackLocation = UltimateResourceFallbackLocation.MainAssembly;
232                 return CultureInfo.InvariantCulture;
233             }
234 #endif
235
236             Contract.Assert(a != null, "assembly != null");
237             string cultureName = null;
238             short fallback = 0;
239
240 #if MONO
241             if (GetNeutralResourcesLanguageAttribute(a, ref cultureName, ref fallback)) {
242 #else
243             if (GetNeutralResourcesLanguageAttribute(((RuntimeAssembly)a).GetNativeHandle(), 
244                                                         JitHelpers.GetStringHandleOnStack(ref cultureName), 
245                                                         out fallback)) {
246 #endif
247                 if ((UltimateResourceFallbackLocation)fallback < UltimateResourceFallbackLocation.MainAssembly || (UltimateResourceFallbackLocation)fallback > UltimateResourceFallbackLocation.Satellite) {
248                     throw new ArgumentException(Environment.GetResourceString("Arg_InvalidNeutralResourcesLanguage_FallbackLoc", fallback));
249                 }
250                 fallbackLocation = (UltimateResourceFallbackLocation)fallback;
251             }
252             else {
253 #if !FEATURE_CORECLR && !MONO
254                 if (FrameworkEventSource.IsInitialized) {
255                     FrameworkEventSource.Log.ResourceManagerNeutralResourceAttributeMissing(a);
256                 }
257 #endif
258                 fallbackLocation = UltimateResourceFallbackLocation.MainAssembly;
259                 return CultureInfo.InvariantCulture;
260             }
261
262             try
263             {
264                 CultureInfo c = CultureInfo.GetCultureInfo(cultureName);
265                 return c;
266             }
267             catch (ArgumentException e)
268             { // we should catch ArgumentException only.
269                 // Note we could go into infinite loops if mscorlib's 
270                 // NeutralResourcesLanguageAttribute is mangled.  If this assert
271                 // fires, please fix the build process for the BCL directory.
272                 if (a == typeof(Object).Assembly)
273                 {
274                     Contract.Assert(false, "mscorlib's NeutralResourcesLanguageAttribute is a malformed culture name! name: \"" + cultureName + "\"  Exception: " + e);
275                     return CultureInfo.InvariantCulture;
276                 }
277
278                 throw new ArgumentException(Environment.GetResourceString("Arg_InvalidNeutralResourcesLanguage_Asm_Culture", a.ToString(), cultureName), e);
279             }
280         }
281
282         // Constructs a new ResourceSet for a given file name.  The logic in
283         // here avoids a ReflectionPermission check for our RuntimeResourceSet
284         // for perf and working set reasons.
285         // Use the assembly to resolve assembly manifest resource references.
286         // Note that is can be null, but probably shouldn't be.
287         // This method could use some refactoring. One thing at a time.
288         [System.Security.SecurityCritical]
289         internal ResourceSet CreateResourceSet(Stream store, Assembly assembly)
290         {
291             Contract.Assert(store != null, "I need a Stream!");
292             // Check to see if this is a Stream the ResourceManager understands,
293             // and check for the correct resource reader type.
294             if (store.CanSeek && store.Length > 4)
295             {
296                 long startPos = store.Position;
297                 
298                 // not disposing because we want to leave stream open
299                 BinaryReader br = new BinaryReader(store);
300                 
301                 // Look for our magic number as a little endian Int32.
302                 int bytes = br.ReadInt32();
303                 if (bytes == ResourceManager.MagicNumber)
304                 {
305                     int resMgrHeaderVersion = br.ReadInt32();
306                     String readerTypeName = null, resSetTypeName = null;
307                     if (resMgrHeaderVersion == ResourceManager.HeaderVersionNumber)
308                     {
309                         br.ReadInt32();  // We don't want the number of bytes to skip.
310                         readerTypeName = br.ReadString();
311                         resSetTypeName = br.ReadString();
312                     }
313                     else if (resMgrHeaderVersion > ResourceManager.HeaderVersionNumber)
314                     {
315                         // Assume that the future ResourceManager headers will
316                         // have two strings for us - the reader type name and
317                         // resource set type name.  Read those, then use the num
318                         // bytes to skip field to correct our position.
319                         int numBytesToSkip = br.ReadInt32();
320                         long endPosition = br.BaseStream.Position + numBytesToSkip;
321
322                         readerTypeName = br.ReadString();
323                         resSetTypeName = br.ReadString();
324
325                         br.BaseStream.Seek(endPosition, SeekOrigin.Begin);
326                     }
327                     else
328                     {
329                         // resMgrHeaderVersion is older than this ResMgr version.
330                         // We should add in backwards compatibility support here.
331
332                         throw new NotSupportedException(Environment.GetResourceString("NotSupported_ObsoleteResourcesFile", _mediator.MainAssembly.GetSimpleName()));
333                     }
334
335                     store.Position = startPos;
336                     // Perf optimization - Don't use Reflection for our defaults.
337                     // Note there are two different sets of strings here - the
338                     // assembly qualified strings emitted by ResourceWriter, and
339                     // the abbreviated ones emitted by InternalResGen.
340                     if (CanUseDefaultResourceClasses(readerTypeName, resSetTypeName))
341                     {
342                         RuntimeResourceSet rs;
343 #if LOOSELY_LINKED_RESOURCE_REFERENCE
344                         rs = new RuntimeResourceSet(store, assembly);
345 #else
346                         rs = new RuntimeResourceSet(store);
347 #endif // LOOSELY_LINKED_RESOURCE_REFERENCE
348                         return rs;
349                     }
350                     else
351                     {
352                         // we do not want to use partial binding here.
353                         Type readerType = Type.GetType(readerTypeName, true);
354                         Object[] args = new Object[1];
355                         args[0] = store;
356                         IResourceReader reader = (IResourceReader)Activator.CreateInstance(readerType, args);
357
358                         Object[] resourceSetArgs =
359 #if LOOSELY_LINKED_RESOURCE_REFERENCE
360                             new Object[2];
361 #else
362  new Object[1];
363 #endif // LOOSELY_LINKED_RESOURCE_REFERENCE
364                         resourceSetArgs[0] = reader;
365 #if LOOSELY_LINKED_RESOURCE_REFERENCE
366                         resourceSetArgs[1] = assembly;
367 #endif // LOOSELY_LINKED_RESOURCE_REFERENCE
368                         Type resSetType;
369                         if (_mediator.UserResourceSet == null)
370                         {
371                             Contract.Assert(resSetTypeName != null, "We should have a ResourceSet type name from the custom resource file here.");
372                             resSetType = Type.GetType(resSetTypeName, true, false);
373                         }
374                         else
375                             resSetType = _mediator.UserResourceSet;
376                         ResourceSet rs = (ResourceSet)Activator.CreateInstance(resSetType,
377                                                                                 BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.CreateInstance,
378                                                                                 null,
379                                                                                 resourceSetArgs,
380                                                                                 null,
381                                                                                 null);
382                         return rs;
383                     }
384                 }
385                 else
386                 {
387                     store.Position = startPos;
388                 }
389
390             }
391
392             if (_mediator.UserResourceSet == null)
393             {
394                 // Explicitly avoid CreateInstance if possible, because it
395                 // requires ReflectionPermission to call private & protected
396                 // constructors.  
397 #if LOOSELY_LINKED_RESOURCE_REFERENCE                
398                 return new RuntimeResourceSet(store, assembly);
399 #else
400                 return new RuntimeResourceSet(store);
401 #endif // LOOSELY_LINKED_RESOURCE_REFERENCE
402             }
403             else
404             {
405                 Object[] args = new Object[2];
406                 args[0] = store;
407                 args[1] = assembly;
408                 try
409                 {
410                     ResourceSet rs = null;
411                     // Add in a check for a constructor taking in an assembly first.
412                     try
413                     {
414                         rs = (ResourceSet)Activator.CreateInstance(_mediator.UserResourceSet, args);
415                         return rs;
416                     }
417                     catch (MissingMethodException) { }
418
419                     args = new Object[1];
420                     args[0] = store;
421                     rs = (ResourceSet)Activator.CreateInstance(_mediator.UserResourceSet, args);
422 #if LOOSELY_LINKED_RESOURCE_REFERENCE
423                     rs.Assembly = assembly;
424 #endif // LOOSELY_LINKED_RESOURCE_REFERENCE
425                     return rs;
426                 }
427                 catch (MissingMethodException e)
428                 {
429                     throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ResMgrBadResSet_Type", _mediator.UserResourceSet.AssemblyQualifiedName), e);
430                 }
431             }
432         }
433
434         [System.Security.SecurityCritical]
435         private Stream GetManifestResourceStream(RuntimeAssembly satellite, String fileName, ref StackCrawlMark stackMark)
436         {
437             Contract.Requires(satellite != null, "satellite shouldn't be null; check caller");
438             Contract.Requires(fileName != null, "fileName shouldn't be null; check caller");
439
440             // If we're looking in the main assembly AND if the main assembly was the person who
441             // created the ResourceManager, skip a security check for private manifest resources.
442             bool canSkipSecurityCheck = (_mediator.MainAssembly == satellite)
443                                         && (_mediator.CallingAssembly == _mediator.MainAssembly);
444
445             Stream stream = satellite.GetManifestResourceStream(_mediator.LocationInfo, fileName, canSkipSecurityCheck, ref stackMark);
446             if (stream == null)
447             {
448                 stream = CaseInsensitiveManifestResourceStreamLookup(satellite, fileName);
449             }
450
451             return stream;
452         }
453
454         // Looks up a .resources file in the assembly manifest using 
455         // case-insensitive lookup rules.  Yes, this is slow.  The metadata
456         // dev lead refuses to make all assembly manifest resource lookups case-insensitive,
457         // even optionally case-insensitive.        
458         [System.Security.SecurityCritical]
459         [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
460         private Stream CaseInsensitiveManifestResourceStreamLookup(RuntimeAssembly satellite, String name)
461         {
462             Contract.Requires(satellite != null, "satellite shouldn't be null; check caller");
463             Contract.Requires(name != null, "name shouldn't be null; check caller");
464
465             StringBuilder sb = new StringBuilder();
466             if (_mediator.LocationInfo != null)
467             {
468                 String nameSpace = _mediator.LocationInfo.Namespace;
469                 if (nameSpace != null)
470                 {
471                     sb.Append(nameSpace);
472                     if (name != null)
473                         sb.Append(Type.Delimiter);
474                 }
475             }
476             sb.Append(name);
477
478             String givenName = sb.ToString();
479             CompareInfo comparer = CultureInfo.InvariantCulture.CompareInfo;
480             String canonicalName = null;
481             foreach (String existingName in satellite.GetManifestResourceNames())
482             {
483                 if (comparer.Compare(existingName, givenName, CompareOptions.IgnoreCase) == 0)
484                 {
485                     if (canonicalName == null)
486                     {
487                         canonicalName = existingName;
488                     }
489                     else
490                     {
491                         throw new MissingManifestResourceException(Environment.GetResourceString("MissingManifestResource_MultipleBlobs", givenName, satellite.ToString()));
492                     }
493                 }
494             }
495
496 #if !FEATURE_CORECLR && !MONO
497             if (FrameworkEventSource.IsInitialized)
498             {
499                 if (canonicalName != null)
500                 {
501                     FrameworkEventSource.Log.ResourceManagerCaseInsensitiveResourceStreamLookupSucceeded(_mediator.BaseName, _mediator.MainAssembly, satellite.GetSimpleName(), givenName);
502                 }
503                 else
504                 {
505                     FrameworkEventSource.Log.ResourceManagerCaseInsensitiveResourceStreamLookupFailed(_mediator.BaseName, _mediator.MainAssembly, satellite.GetSimpleName(), givenName);
506                 }
507             }
508 #endif
509
510             if (canonicalName == null)
511             {
512                 return null;
513             }
514             // If we're looking in the main assembly AND if the main
515             // assembly was the person who created the ResourceManager,
516             // skip a security check for private manifest resources.
517             bool canSkipSecurityCheck = _mediator.MainAssembly == satellite && _mediator.CallingAssembly == _mediator.MainAssembly;
518             StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
519             Stream s = satellite.GetManifestResourceStream(canonicalName, ref stackMark, canSkipSecurityCheck);
520             // GetManifestResourceStream will return null if we don't have 
521             // permission to read this stream from the assembly.  For example,
522             // if the stream is private and we're trying to access it from another
523             // assembly (ie, ResMgr in mscorlib accessing anything else), we 
524             // require Reflection TypeInformation permission to be able to read 
525             // this.  <
526
527
528
529
530 #if !FEATURE_CORECLR && !MONO
531             if (s!=null) {
532                 if (FrameworkEventSource.IsInitialized)
533                 {
534                     FrameworkEventSource.Log.ResourceManagerManifestResourceAccessDenied(_mediator.BaseName, _mediator.MainAssembly, satellite.GetSimpleName(), canonicalName);
535                 }
536             }
537 #endif
538             return s;
539         }
540
541         [System.Security.SecurityCritical]
542         [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var have to be marked non-inlineable
543         private RuntimeAssembly GetSatelliteAssembly(CultureInfo lookForCulture, ref StackCrawlMark stackMark)
544         {
545             if (!_mediator.LookedForSatelliteContractVersion)
546             {
547                 _mediator.SatelliteContractVersion = _mediator.ObtainSatelliteContractVersion(_mediator.MainAssembly);
548                 _mediator.LookedForSatelliteContractVersion = true;
549             }
550
551             RuntimeAssembly satellite = null;
552             String satAssemblyName = GetSatelliteAssemblyName();
553
554             // Look up the satellite assembly, but don't let problems
555             // like a partially signed satellite assembly stop us from
556             // doing fallback and displaying something to the user.
557             // Yet also somehow log this error for a developer.
558             try
559             {
560                 satellite = _mediator.MainAssembly.InternalGetSatelliteAssembly(satAssemblyName, lookForCulture, _mediator.SatelliteContractVersion, false, ref stackMark);
561             }
562
563             // Jun 08: for cases other than ACCESS_DENIED, we'll assert instead of throw to give release builds more opportunity to fallback.
564             // 
565
566 #pragma warning disable 168
567             catch (FileLoadException fle)
568 #pragma warning restore
569             {
570 #if !MONO                
571                 // Ignore cases where the loader gets an access
572                 // denied back from the OS.  This showed up for
573                 // href-run exe's at one point.  
574                 int hr = fle._HResult;
575                 if (hr != Win32Native.MakeHRFromErrorCode(Win32Native.ERROR_ACCESS_DENIED))
576                 {
577                     Contract.Assert(false, "[This assert catches satellite assembly build/deployment problems - report this message to your build lab & loc engineer]" + Environment.NewLine + "GetSatelliteAssembly failed for culture " + lookForCulture.Name + " and version " + (_mediator.SatelliteContractVersion == null ? _mediator.MainAssembly.GetVersion().ToString() : _mediator.SatelliteContractVersion.ToString()) + " of assembly " + _mediator.MainAssembly.GetSimpleName() + " with error code 0x" + hr.ToString("X", CultureInfo.InvariantCulture) + Environment.NewLine + "Exception: " + fle);
578                 }
579 #endif
580             }
581
582             // Don't throw for zero-length satellite assemblies, for compat with v1
583             catch (BadImageFormatException bife)
584             {
585                 Contract.Assert(false, "[This assert catches satellite assembly build/deployment problems - report this message to your build lab & loc engineer]" + Environment.NewLine + "GetSatelliteAssembly failed for culture " + lookForCulture.Name + " and version " + (_mediator.SatelliteContractVersion == null ? _mediator.MainAssembly.GetVersion().ToString() : _mediator.SatelliteContractVersion.ToString()) + " of assembly " + _mediator.MainAssembly.GetSimpleName() + Environment.NewLine + "Exception: " + bife);
586             }
587
588 #if !FEATURE_CORECLR && !MONO
589             if (FrameworkEventSource.IsInitialized)
590             {
591                 if (satellite != null)
592                 {
593                     FrameworkEventSource.Log.ResourceManagerGetSatelliteAssemblySucceeded(_mediator.BaseName, _mediator.MainAssembly, lookForCulture.Name, satAssemblyName);
594                 }
595                 else
596                 {
597                     FrameworkEventSource.Log.ResourceManagerGetSatelliteAssemblyFailed(_mediator.BaseName, _mediator.MainAssembly, lookForCulture.Name, satAssemblyName);
598                 }
599             }
600 #endif
601
602             return satellite;
603         }
604
605         // Perf optimization - Don't use Reflection for most cases with
606         // our .resources files.  This makes our code run faster and we can
607         // creating a ResourceReader via Reflection.  This would incur
608         // a security check (since the link-time check on the constructor that
609         // takes a String is turned into a full demand with a stack walk)
610         // and causes partially trusted localized apps to fail.
611         private bool CanUseDefaultResourceClasses(String readerTypeName, String resSetTypeName)
612         {
613             Contract.Assert(readerTypeName != null, "readerTypeName shouldn't be null; check caller");
614             Contract.Assert(resSetTypeName != null, "resSetTypeName shouldn't be null; check caller");
615
616             if (_mediator.UserResourceSet != null)
617                 return false;
618
619             // Ignore the actual version of the ResourceReader and 
620             // RuntimeResourceSet classes.  Let those classes deal with
621             // versioning themselves.
622             AssemblyName mscorlib = new AssemblyName(ResourceManager.MscorlibName);
623
624             if (readerTypeName != null)
625             {
626                 if (!ResourceManager.CompareNames(readerTypeName, ResourceManager.ResReaderTypeName, mscorlib))
627                     return false;
628             }
629
630             if (resSetTypeName != null)
631             {
632                 if (!ResourceManager.CompareNames(resSetTypeName, ResourceManager.ResSetTypeName, mscorlib))
633                     return false;
634             }
635
636             return true;
637         }
638
639         [System.Security.SecurityCritical]
640         private String GetSatelliteAssemblyName()
641         {
642             String satAssemblyName = _mediator.MainAssembly.GetSimpleName();
643                 satAssemblyName += ".resources";
644             return satAssemblyName;
645         }
646
647         [System.Security.SecurityCritical]
648         private void HandleSatelliteMissing()
649         {
650             String satAssemName = _mediator.MainAssembly.GetSimpleName() + ".resources.dll";
651             if (_mediator.SatelliteContractVersion != null)
652             {
653                 satAssemName += ", Version=" + _mediator.SatelliteContractVersion.ToString();
654             }
655
656             AssemblyName an = new AssemblyName();
657             an.SetPublicKey(_mediator.MainAssembly.GetPublicKey());
658             byte[] token = an.GetPublicKeyToken();
659
660             int iLen = token.Length;
661             StringBuilder publicKeyTok = new StringBuilder(iLen * 2);
662             for (int i = 0; i < iLen; i++)
663             {
664                 publicKeyTok.Append(token[i].ToString("x", CultureInfo.InvariantCulture));
665             }
666             satAssemName += ", PublicKeyToken=" + publicKeyTok;
667
668             String missingCultureName = _mediator.NeutralResourcesCulture.Name;
669             if (missingCultureName.Length == 0)
670             {
671                 missingCultureName = "<invariant>";
672             }
673             throw new MissingSatelliteAssemblyException(Environment.GetResourceString("MissingSatelliteAssembly_Culture_Name", _mediator.NeutralResourcesCulture, satAssemName), missingCultureName);
674         }
675
676         [System.Security.SecurityCritical]  // auto-generated
677         private void HandleResourceStreamMissing(String fileName)
678         {
679             // Keep people from bothering me about resources problems
680             if (_mediator.MainAssembly == typeof(Object).Assembly && _mediator.BaseName.Equals("mscorlib"))
681             {
682                 // This would break CultureInfo & all our exceptions.
683                 Contract.Assert(false, "Couldn't get mscorlib" + ResourceManager.ResFileExtension + " from mscorlib's assembly" + Environment.NewLine + Environment.NewLine + "Are you building the runtime on your machine?  Chances are the BCL directory didn't build correctly.  Type 'build -c' in the BCL directory.  If you get build errors, look at buildd.log.  If you then can't figure out what's wrong (and you aren't changing the assembly-related metadata code), ask a BCL dev.\n\nIf you did NOT build the runtime, you shouldn't be seeing this and you've found a bug.");
684                 
685                 // We cannot continue further - simply FailFast.
686                 string mesgFailFast = "mscorlib" + ResourceManager.ResFileExtension + " couldn't be found!  Large parts of the BCL won't work!";
687                 System.Environment.FailFast(mesgFailFast);
688             }
689             // We really don't think this should happen - we always
690             // expect the neutral locale's resources to be present.
691             String resName = String.Empty;
692             if (_mediator.LocationInfo != null && _mediator.LocationInfo.Namespace != null)
693                 resName = _mediator.LocationInfo.Namespace + Type.Delimiter;
694             resName += fileName;
695             throw new MissingManifestResourceException(Environment.GetResourceString("MissingManifestResource_NoNeutralAsm", resName, _mediator.MainAssembly.GetSimpleName()));
696         }
697
698 #if MONO
699         static bool GetNeutralResourcesLanguageAttribute (Assembly assembly, ref string cultureName, ref short fallbackLocation)
700         {
701             var ca = assembly.GetCustomAttribute<NeutralResourcesLanguageAttribute> ();
702             if (ca == null)
703                 return false;
704
705             cultureName = ca.CultureName;
706             fallbackLocation = (short) ca.Location;
707             return true;
708         }
709 #else
710             [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
711             [System.Security.SecurityCritical]  // Our security team doesn't yet allow safe-critical P/Invoke methods.
712             [ResourceExposure(ResourceScope.None)]
713             [System.Security.SuppressUnmanagedCodeSecurity]
714             [return: MarshalAs(UnmanagedType.Bool)]
715             internal static extern bool GetNeutralResourcesLanguageAttribute(RuntimeAssembly assemblyHandle, StringHandleOnStack cultureName, out short fallbackLocation);
716 #endif
717     }
718 }