Merge pull request #3213 from henricm/fix-for-win-securestring-to-bstr
[mono.git] / mcs / class / referencesource / System / InternalApis / Clr / inc / AppContextDefaultValues.cs
1 // ==++==
2 // 
3 //   Copyright (c) Microsoft Corporation.  All rights reserved.
4 // 
5 // ==--==
6
7 // There are cases where we have multiple assemblies that are going to import this file and 
8 // if they are going to also have InternalsVisibleTo between them, there will be a compiler warning
9 // that the type is found both in the source and in a referenced assembly. The compiler will prefer 
10 // the version of the type defined in the source
11 //
12 // In order to disable the warning for this type we are disabling this warning for this entire file.
13 #pragma warning disable 436
14
15 using System;
16 using System.Collections.Generic;
17
18 namespace System
19 {
20     internal static partial class AppContextDefaultValues
21     {
22         public static void PopulateDefaultValues()
23         {
24             string platformIdentifier, profile;
25             int version;
26
27             ParseTargetFrameworkName(out platformIdentifier, out profile, out version);
28
29             // Call into each library to populate their default switches
30             PopulateDefaultValuesPartial(platformIdentifier, profile, version);
31         }
32
33         /// <summary>
34         /// We have this separate method for getting the parsed elements out of the TargetFrameworkName so we can
35         /// more easily support this on other platforms.
36         /// </summary>
37         private static void ParseTargetFrameworkName(out string identifier, out string profile, out int version)
38         {
39             string targetFrameworkMoniker = AppDomain.CurrentDomain.SetupInformation.TargetFrameworkName;
40
41             // If we don't have a TFM then we should default to the 4.0 behavior where all quirks are turned on.
42             if (!TryParseFrameworkName(targetFrameworkMoniker, out identifier, out version, out profile))
43             {
44 #if FEATURE_CORECLR
45                 if (CompatibilitySwitches.UseLatestBehaviorWhenTFMNotSpecified)
46                 {
47                     // If we want to use the latest behavior it is enough to set the value of the switch to string.Empty.
48                     // When the get to the caller of this method (PopulateDefaultValuesPartial) we are going to use the 
49                     // identifier we just set to decide which switches to turn on. By having an empty string as the 
50                     // identifier we are simply saying -- don't turn on any switches, and we are going to get the latest
51                     // behavior for all the switches
52                     identifier = string.Empty;
53                 }
54                 else
55 #endif
56                 {
57                     identifier = ".NETFramework";
58                     version = 40000;
59                     profile = string.Empty;
60                 }
61             }
62         }
63
64         // This code was a constructor copied from the FrameworkName class, which is located in System.dll.
65         // Parses strings in the following format: "<identifier>, Version=[v|V]<version>, Profile=<profile>"
66         //  - The identifier and version is required, profile is optional
67         //  - Only three components are allowed.
68         //  - The version string must be in the System.Version format; an optional "v" or "V" prefix is allowed
69         private static bool TryParseFrameworkName(String frameworkName, out String identifier, out int version, out String profile)
70         {
71             // For parsing a target Framework moniker, from the FrameworkName class
72             const char c_componentSeparator = ',';
73             const char c_keyValueSeparator = '=';
74             const char c_versionValuePrefix = 'v';
75             const String c_versionKey = "Version";
76             const String c_profileKey = "Profile";
77
78             identifier = profile = string.Empty;
79             version = 0;
80
81             if (frameworkName == null || frameworkName.Length == 0)
82             {
83                 return false;
84             }
85
86             String[] components = frameworkName.Split(c_componentSeparator);
87             version = 0;
88
89             // Identifer and Version are required, Profile is optional.
90             if (components.Length < 2 || components.Length > 3)
91             {
92                 return false;
93             }
94
95             //
96             // 1) Parse the "Identifier", which must come first. Trim any whitespace
97             //
98             identifier = components[0].Trim();
99
100             if (identifier.Length == 0)
101             {
102                 return false;
103             }
104
105             bool versionFound = false;
106             profile = null;
107
108             // 
109             // The required "Version" and optional "Profile" component can be in any order
110             //
111             for (int i = 1; i < components.Length; i++)
112             {
113                 // Get the key/value pair separated by '='
114                 string[] keyValuePair = components[i].Split(c_keyValueSeparator);
115
116                 if (keyValuePair.Length != 2)
117                 {
118                     return false;
119                 }
120
121                 // Get the key and value, trimming any whitespace
122                 string key = keyValuePair[0].Trim();
123                 string value = keyValuePair[1].Trim();
124
125                 //
126                 // 2) Parse the required "Version" key value
127                 //
128                 if (key.Equals(c_versionKey, StringComparison.OrdinalIgnoreCase))
129                 {
130                     versionFound = true;
131
132                     // Allow the version to include a 'v' or 'V' prefix...
133                     if (value.Length > 0 && (value[0] == c_versionValuePrefix || value[0] == 'V'))
134                     {
135                         value = value.Substring(1);
136                     }
137                     Version realVersion = new Version(value);
138                     // The version class will represent some unset values as -1 internally (instead of 0).
139                     version = realVersion.Major * 10000;
140                     if (realVersion.Minor > 0)
141                         version += realVersion.Minor * 100;
142                     if (realVersion.Build > 0)
143                         version += realVersion.Build;
144                 }
145                 //
146                 // 3) Parse the optional "Profile" key value
147                 //
148                 else if (key.Equals(c_profileKey, StringComparison.OrdinalIgnoreCase))
149                 {
150                     if (!String.IsNullOrEmpty(value))
151                     {
152                         profile = value;
153                     }
154                 }
155                 else
156                 {
157                     return false;
158                 }
159             }
160
161             if (!versionFound)
162             {
163                 return false;
164             }
165
166             return true;
167         }
168
169         // This is a partial method. Platforms (such as Desktop) can provide an implementation of it that will read override value
170         // from whatever mechanism is available on that platform. If no implementation is provided, the compiler is going to remove the calls
171         // to it from the code
172         static partial void TryGetSwitchOverridePartial(string switchName, ref bool overrideFound, ref bool overrideValue);
173
174         /// This is a partial method. This method is responsible for populating the default values based on a TFM.
175         /// It is partial because each library should define this method in their code to contain their defaults.
176         static partial void PopulateDefaultValuesPartial(string platformIdentifier, string profile, int version);
177     }
178 }
179
180 #pragma warning restore 436