1 //------------------------------------------------------------------------------
2 // <copyright file="Compiler.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 // <owner current="true" primary="true">Microsoft</owner>
6 //------------------------------------------------------------------------------
8 namespace System.Xml.Serialization {
9 using System.Reflection;
10 using System.Reflection.Emit;
11 using System.Collections;
15 using System.ComponentModel;
16 using System.CodeDom.Compiler;
17 using System.Security;
18 using System.Security.Permissions;
19 using System.Diagnostics;
20 using System.Security.Principal;
21 using System.Security.Policy;
22 using System.Threading;
23 using System.Xml.Serialization.Configuration;
24 using System.Globalization;
25 using System.Runtime.Versioning;
26 using System.Runtime.CompilerServices;
28 internal class Compiler {
29 bool debugEnabled = DiagnosticsSwitches.KeepTempFiles.Enabled;
30 Hashtable imports = new Hashtable();
31 StringWriter writer = new StringWriter(CultureInfo.InvariantCulture);
33 [ResourceExposure(ResourceScope.Machine)]
34 protected string[] Imports {
36 string[] array = new string[imports.Values.Count];
37 imports.Values.CopyTo(array, 0);
42 // SxS: This method does not take any resource name and does not expose any resources to the caller.
43 // It's OK to suppress the SxS warning.
44 [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
45 [ResourceExposure(ResourceScope.None)]
46 internal void AddImport(Type type, Hashtable types) {
49 if (TypeScope.IsKnownType(type))
51 if (types[type] != null)
54 Type baseType = type.BaseType;
56 AddImport(baseType, types);
58 Type declaringType = type.DeclaringType;
59 if (declaringType != null)
60 AddImport(declaringType, types);
62 foreach (Type intf in type.GetInterfaces())
63 AddImport(intf, types);
65 ConstructorInfo[] ctors = type.GetConstructors();
66 for (int i = 0; i < ctors.Length; i++) {
67 ParameterInfo[] parms = ctors[i].GetParameters();
68 for (int j = 0; j < parms.Length; j++) {
69 AddImport(parms[j].ParameterType, types);
73 if (type.IsGenericType) {
74 Type[] arguments = type.GetGenericArguments();
75 for (int i = 0; i < arguments.Length; i++) {
76 AddImport(arguments[i], types);
80 TempAssembly.FileIOPermission.Assert();
81 Module module = type.Module;
82 Assembly assembly = module.Assembly;
83 if (DynamicAssemblies.IsTypeDynamic(type)) {
84 DynamicAssemblies.Add(assembly);
88 object[] typeForwardedFromAttribute = type.GetCustomAttributes(typeof(TypeForwardedFromAttribute), false);
89 if (typeForwardedFromAttribute.Length > 0)
91 TypeForwardedFromAttribute originalAssemblyInfo = typeForwardedFromAttribute[0] as TypeForwardedFromAttribute;
92 Assembly originalAssembly = Assembly.Load(originalAssemblyInfo.AssemblyFullName);
93 imports[originalAssembly] = originalAssembly.Location;
96 imports[assembly] = assembly.Location;
99 // SxS: This method does not take any resource name and does not expose any resources to the caller.
100 // It's OK to suppress the SxS warning.
101 [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
102 [ResourceExposure(ResourceScope.None)]
103 internal void AddImport(Assembly assembly) {
104 TempAssembly.FileIOPermission.Assert();
105 imports[assembly] = assembly.Location;
108 internal TextWriter Source {
109 get { return writer; }
112 internal void Close() { }
114 [ResourceConsumption(ResourceScope.Machine)]
115 [ResourceExposure(ResourceScope.Machine)]
116 internal static string GetTempAssemblyPath(string baseDir, Assembly assembly, string defaultNamespace) {
117 if (assembly.IsDynamic) {
118 throw new InvalidOperationException(Res.GetString(Res.XmlPregenAssemblyDynamic));
121 PermissionSet perms = new PermissionSet(PermissionState.None);
122 perms.AddPermission(new FileIOPermission(PermissionState.Unrestricted));
123 perms.AddPermission(new EnvironmentPermission(PermissionState.Unrestricted));
127 if (baseDir != null && baseDir.Length > 0) {
128 // check that the dirsctory exists
129 if (!Directory.Exists(baseDir)) {
130 throw new UnauthorizedAccessException(Res.GetString(Res.XmlPregenMissingDirectory, baseDir));
134 baseDir = Path.GetTempPath();
135 // check that the dirsctory exists
136 if (!Directory.Exists(baseDir)) {
137 throw new UnauthorizedAccessException(Res.GetString(Res.XmlPregenMissingTempDirectory));
142 baseDir = Path.Combine (baseDir, GetTempAssemblyName(assembly.GetName(), defaultNamespace));
144 if (baseDir.EndsWith("\\", StringComparison.Ordinal))
145 baseDir += GetTempAssemblyName(assembly.GetName(), defaultNamespace);
147 baseDir += "\\" + GetTempAssemblyName(assembly.GetName(), defaultNamespace);
151 CodeAccessPermission.RevertAssert();
153 return baseDir + ".dll";
156 internal static string GetTempAssemblyName(AssemblyName parent, string ns) {
157 return parent.Name + ".XmlSerializers" + (ns == null || ns.Length == 0 ? "" : "." + ns.GetHashCode());
160 // SxS: This method does not take any resource name and does not expose any resources to the caller.
161 // It's OK to suppress the SxS warning.
162 [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
163 [ResourceExposure(ResourceScope.None)]
164 internal Assembly Compile(Assembly parent, string ns, XmlSerializerCompilerParameters xmlParameters, Evidence evidence) {
165 CodeDomProvider codeProvider = new Microsoft.CSharp.CSharpCodeProvider();
166 CompilerParameters parameters = xmlParameters.CodeDomParameters;
167 parameters.ReferencedAssemblies.AddRange(Imports);
170 parameters.GenerateInMemory = false;
171 parameters.IncludeDebugInformation = true;
172 parameters.TempFiles.KeepFiles = true;
174 PermissionSet perms = new PermissionSet(PermissionState.None);
175 if (xmlParameters.IsNeedTempDirAccess) {
176 perms.AddPermission(TempAssembly.FileIOPermission);
178 perms.AddPermission(new EnvironmentPermission(PermissionState.Unrestricted));
179 perms.AddPermission(new SecurityPermission(SecurityPermissionFlag.UnmanagedCode));
180 perms.AddPermission(new SecurityPermission(SecurityPermissionFlag.ControlEvidence));
183 if (parent != null && (parameters.OutputAssembly == null || parameters.OutputAssembly.Length ==0)) {
184 string assemblyName = AssemblyNameFromOptions(parameters.CompilerOptions);
185 if (assemblyName == null)
186 assemblyName = GetTempAssemblyPath(parameters.TempFiles.TempDir, parent, ns);
188 parameters.OutputAssembly = assemblyName;
191 if (parameters.CompilerOptions == null || parameters.CompilerOptions.Length == 0)
192 parameters.CompilerOptions = "/nostdlib";
194 parameters.CompilerOptions += " /nostdlib";
196 parameters.CompilerOptions += " /D:_DYNAMIC_XMLSERIALIZER_COMPILATION";
197 #pragma warning disable 618
198 parameters.Evidence = evidence;
199 #pragma warning restore 618
200 CompilerResults results = null;
201 Assembly assembly = null;
203 results = codeProvider.CompileAssemblyFromSource(parameters, writer.ToString());
204 // check the output for errors or a certain level-1 warning (1595)
205 if (results.Errors.Count > 0) {
206 StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture);
207 stringWriter.WriteLine(Res.GetString(Res.XmlCompilerError, results.NativeCompilerReturnValue.ToString(CultureInfo.InvariantCulture)));
208 bool foundOne = false;
209 foreach (CompilerError e in results.Errors) {
210 // clear filename. This makes ToString() print just error number and message.
212 if (!e.IsWarning || e.ErrorNumber == "CS1595") {
214 stringWriter.WriteLine(e.ToString());
218 throw new InvalidOperationException(stringWriter.ToString());
221 assembly = results.CompiledAssembly;
223 catch (UnauthorizedAccessException) {
224 // try to get the user token
225 string user = GetCurrentUser();
226 if (user == null || user.Length == 0) {
227 throw new UnauthorizedAccessException(Res.GetString(Res.XmlSerializerAccessDenied));
230 throw new UnauthorizedAccessException(Res.GetString(Res.XmlIdentityAccessDenied, user));
233 catch (FileLoadException fle) {
234 throw new InvalidOperationException(Res.GetString(Res.XmlSerializerCompileFailed), fle);
237 CodeAccessPermission.RevertAssert();
239 // somehow we got here without generating an assembly
240 if (assembly == null) throw new InvalidOperationException(Res.GetString(Res.XmlInternalError));
245 static string AssemblyNameFromOptions(string options) {
246 if (options == null || options.Length == 0)
249 string outName = null;
250 string[] flags = options.ToLower(CultureInfo.InvariantCulture).Split(null);
251 for (int i = 0; i < flags.Length; i++) {
252 string val = flags[i].Trim();
253 if (val.StartsWith("/out:", StringComparison.Ordinal)) {
254 outName = val.Substring(5);
260 internal static string GetCurrentUser()
264 WindowsIdentity id = WindowsIdentity.GetCurrent();
265 if (id != null && id.Name != null)
268 catch (Exception e) {
269 if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException) {
273 #endif // !FEATURE_PAL