summaryrefslogtreecommitdiff
path: root/src/mscorlib/src/System/Resources/FileBasedResourceGroveler.cs
blob: 76bf0008f995d2c2a224a37bd585d2f11ac6273e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

/*============================================================
**
** 
** 
**
**
** Purpose: Searches for resources on disk, used for file-
** based resource lookup.
**
** 
===========================================================*/
namespace System.Resources {    
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.IO;
    using System.Globalization;
    using System.Runtime.CompilerServices;
    using System.Runtime.Versioning;
    using System.Text;
    using System.Threading;
    using System.Diagnostics;
    using System.Diagnostics.Contracts;

    internal class FileBasedResourceGroveler : IResourceGroveler
    {
        private ResourceManager.ResourceManagerMediator _mediator;

        public FileBasedResourceGroveler(ResourceManager.ResourceManagerMediator mediator)
        {
            Debug.Assert(mediator != null, "mediator shouldn't be null; check caller");
            _mediator = mediator;
        }

        // Consider modifying IResourceGroveler interface (hence this method signature) when we figure out 
        // serialization compat story for moving ResourceManager members to either file-based or 
        // manifest-based classes. Want to continue tightening the design to get rid of unused params.
        public ResourceSet GrovelForResourceSet(CultureInfo culture, Dictionary<String, ResourceSet> localResourceSets, bool tryParents, bool createIfNotExists, ref StackCrawlMark stackMark) 
        {
            Debug.Assert(culture != null, "culture shouldn't be null; check caller");

            String fileName = null;
            ResourceSet rs = null;

            // Don't use Assembly manifest, but grovel on disk for a file.
            try
            {
                new System.Security.Permissions.FileIOPermission(System.Security.Permissions.PermissionState.Unrestricted).Assert();

                // Create new ResourceSet, if a file exists on disk for it.
                String tempFileName = _mediator.GetResourceFileName(culture);
                fileName = FindResourceFile(culture, tempFileName);
                if (fileName == null)
                {
                    if (tryParents)
                    {
                        // If we've hit top of the Culture tree, return.
                        if (culture.HasInvariantCultureName)
                        {
                            // We really don't think this should happen - we always
                            // expect the neutral locale's resources to be present.
                            throw new MissingManifestResourceException(Environment.GetResourceString("MissingManifestResource_NoNeutralDisk") + Environment.NewLine + "baseName: " + _mediator.BaseNameField + "  locationInfo: " + (_mediator.LocationInfo == null ? "<null>" : _mediator.LocationInfo.FullName) + "  fileName: " + _mediator.GetResourceFileName(culture));
                        }
                    }
                }
                else
                {
                    rs = CreateResourceSet(fileName);
                }
                return rs;
            }
            finally
            {
                System.Security.CodeAccessPermission.RevertAssert();
            }
        }

        // Given a CultureInfo, it generates the path &; file name for 
        // the .resources file for that CultureInfo.  This method will grovel
        // the disk looking for the correct file name & path.  Uses CultureInfo's
        // Name property.  If the module directory was set in the ResourceManager 
        // constructor, we'll look there first.  If it couldn't be found in the module
        // diretory or the module dir wasn't provided, look in the current
        // directory.

        private String FindResourceFile(CultureInfo culture, String fileName)
        {
            Debug.Assert(culture != null, "culture shouldn't be null; check caller");
            Debug.Assert(fileName != null, "fileName shouldn't be null; check caller");

            // If we have a moduleDir, check there first.  Get module fully 
            // qualified name, append path to that.
            if (_mediator.ModuleDir != null)
            {
#if _DEBUG
                if (ResourceManager.DEBUG >= 3)
                    BCLDebug.Log("FindResourceFile: checking module dir: \""+_mediator.ModuleDir+'\"');
#endif

                String path = Path.Combine(_mediator.ModuleDir, fileName);
                if (File.Exists(path))
                {
#if _DEBUG
                    if (ResourceManager.DEBUG >= 3)
                        BCLDebug.Log("Found resource file in module dir!  "+path);
#endif
                    return path;
                }
            }

#if _DEBUG
            if (ResourceManager.DEBUG >= 3)
                BCLDebug.Log("Couldn't find resource file in module dir, checking .\\"+fileName);
#endif

            // look in .
            if (File.Exists(fileName))
                return fileName;

            return null;  // give up.
        }

        // Constructs a new ResourceSet for a given file name.  The logic in
        // here avoids a ReflectionPermission check for our RuntimeResourceSet
        // for perf and working set reasons.
        private ResourceSet CreateResourceSet(String file)
        {
            Debug.Assert(file != null, "file shouldn't be null; check caller");

            if (_mediator.UserResourceSet == null)
            {
                // Explicitly avoid CreateInstance if possible, because it
                // requires ReflectionPermission to call private & protected
                // constructors.  
                return new RuntimeResourceSet(file);
            }
            else
            {
                Object[] args = new Object[1];
                args[0] = file;
                try
                {
                    return (ResourceSet)Activator.CreateInstance(_mediator.UserResourceSet, args);
                }
                catch (MissingMethodException e)
                {
                    throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ResMgrBadResSet_Type", _mediator.UserResourceSet.AssemblyQualifiedName), e);
                }
            }
        }
    }
}