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