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