**** Merged from MCS ****
[mono-project.git] / mcs / class / System.Web / System.Web.UI / TemplateParser.cs
blob6402b7f84f808349e5ea39def745f01bb0051e27
1 //
2 // System.Web.UI.TemplateParser
3 //
4 // Authors:
5 // Duncan Mak (duncan@ximian.com)
6 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 //
8 // (C) 2002,2003 Ximian, Inc. (http://www.ximian.com)
9 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 //
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 //
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 using System;
32 using System.CodeDom.Compiler;
33 using System.Collections;
34 using System.IO;
35 using System.Reflection;
36 using System.Web;
37 using System.Web.Compilation;
38 using System.Web.Configuration;
39 using System.Web.Util;
41 namespace System.Web.UI
43 public abstract class TemplateParser : BaseParser
45 string inputFile;
46 string text;
47 string privateBinPath;
48 Hashtable mainAttributes;
49 ArrayList dependencies;
50 ArrayList assemblies;
51 Hashtable anames;
52 ArrayList imports;
53 ArrayList interfaces;
54 ArrayList scripts;
55 Type baseType;
56 string className;
57 RootBuilder rootBuilder;
58 bool debug;
59 string compilerOptions;
60 string language;
61 bool output_cache;
62 int oc_duration;
63 string oc_header, oc_custom, oc_param, oc_controls;
64 bool oc_shared;
65 OutputCacheLocation oc_location;
66 Assembly srcAssembly;
67 int appAssemblyIndex = -1;
69 internal TemplateParser ()
71 imports = new ArrayList ();
72 imports.Add ("System");
73 imports.Add ("System.Collections");
74 imports.Add ("System.Collections.Specialized");
75 imports.Add ("System.Configuration");
76 imports.Add ("System.Text");
77 imports.Add ("System.Text.RegularExpressions");
78 imports.Add ("System.Web");
79 imports.Add ("System.Web.Caching");
80 imports.Add ("System.Web.Security");
81 imports.Add ("System.Web.SessionState");
82 imports.Add ("System.Web.UI");
83 imports.Add ("System.Web.UI.WebControls");
84 imports.Add ("System.Web.UI.HtmlControls");
86 assemblies = new ArrayList ();
87 assemblies.AddRange (CompilationConfig.Assemblies);
88 if (CompilationConfig.AssembliesInBin)
89 AddAssembliesInBin ();
91 language = CompilationConfig.DefaultLanguage;
94 internal void AddApplicationAssembly ()
96 string location = Context.ApplicationInstance.AssemblyLocation;
97 if (location != typeof (TemplateParser).Assembly.Location) {
98 appAssemblyIndex = assemblies.Add (location);
102 protected abstract Type CompileIntoType ();
104 internal virtual void HandleOptions (object obj)
108 internal static string GetOneKey (Hashtable tbl)
110 foreach (object key in tbl.Keys)
111 return key.ToString ();
113 return null;
116 internal virtual void AddDirective (string directive, Hashtable atts)
118 if (String.Compare (directive, DefaultDirectiveName, true) == 0) {
119 if (mainAttributes != null)
120 ThrowParseException ("Only 1 " + DefaultDirectiveName + " is allowed");
122 mainAttributes = atts;
123 ProcessMainAttributes (mainAttributes);
124 return;
127 int cmp = String.Compare ("Assembly", directive, true);
128 if (cmp == 0) {
129 string name = GetString (atts, "Name", null);
130 string src = GetString (atts, "Src", null);
132 if (atts.Count > 0)
133 ThrowParseException ("Attribute " + GetOneKey (atts) + " unknown.");
135 if (name == null && src == null)
136 ThrowParseException ("You gotta specify Src or Name");
138 if (name != null && src != null)
139 ThrowParseException ("Src and Name cannot be used together");
141 if (name != null) {
142 AddAssemblyByName (name);
143 } else {
144 GetAssemblyFromSource (src);
147 return;
150 cmp = String.Compare ("Import", directive, true);
151 if (cmp == 0) {
152 string namesp = GetString (atts, "Namespace", null);
153 if (atts.Count > 0)
154 ThrowParseException ("Attribute " + GetOneKey (atts) + " unknown.");
156 if (namesp != null && namesp != "")
157 AddImport (namesp);
158 return;
161 cmp = String.Compare ("Implements", directive, true);
162 if (cmp == 0) {
163 string ifacename = GetString (atts, "Interface", "");
165 if (atts.Count > 0)
166 ThrowParseException ("Attribute " + GetOneKey (atts) + " unknown.");
168 Type iface = LoadType (ifacename);
169 if (iface == null)
170 ThrowParseException ("Cannot find type " + ifacename);
172 if (!iface.IsInterface)
173 ThrowParseException (iface + " is not an interface");
175 AddInterface (iface.FullName);
176 return;
179 cmp = String.Compare ("OutputCache", directive, true);
180 if (cmp == 0) {
181 output_cache = true;
183 if (atts ["Duration"] == null)
184 ThrowParseException ("The directive is missing a 'duration' attribute.");
185 if (atts ["VaryByParam"] == null)
186 ThrowParseException ("This directive is missing a 'VaryByParam' " +
187 "attribute, which should be set to \"none\", \"*\", " +
188 "or a list of name/value pairs.");
190 foreach (DictionaryEntry entry in atts) {
191 string key = (string) entry.Key;
192 switch (key.ToLower ()) {
193 case "duration":
194 oc_duration = Int32.Parse ((string) entry.Value);
195 if (oc_duration < 1)
196 ThrowParseException ("The 'duration' attribute must be set " +
197 "to a positive integer value");
198 break;
199 case "varybyparam":
200 oc_param = (string) entry.Value;
201 if (String.Compare (oc_param, "none") == 0)
202 oc_param = null;
203 break;
204 case "varybyheader":
205 oc_header = (string) entry.Value;
206 break;
207 case "varybycustom":
208 oc_custom = (string) entry.Value;
209 break;
210 case "location":
211 if (!(this is PageParser))
212 goto default;
214 try {
215 oc_location = (OutputCacheLocation) Enum.Parse (
216 typeof (OutputCacheLocation), (string) entry.Value, true);
217 } catch {
218 ThrowParseException ("The 'location' attribute is case sensitive and " +
219 "must be one of the following values: Any, Client, " +
220 "Downstream, Server, None, ServerAndClient.");
222 break;
223 case "varybycontrol":
224 if (this is PageParser)
225 goto default;
227 oc_controls = (string) entry.Value;
228 break;
229 case "shared":
230 if (this is PageParser)
231 goto default;
233 try {
234 oc_shared = Boolean.Parse ((string) entry.Value);
235 } catch {
236 ThrowParseException ("The 'shared' attribute is case sensitive" +
237 " and must be set to 'true' or 'false'.");
239 break;
240 default:
241 ThrowParseException ("The '" + key + "' attribute is not " +
242 "supported by the 'Outputcache' directive.");
243 break;
248 return;
251 ThrowParseException ("Unknown directive: " + directive);
254 internal Type LoadType (string typeName)
256 // First try loaded assemblies, then try assemblies in Bin directory.
257 Type type = null;
258 bool seenBin = false;
259 Assembly [] assemblies = AppDomain.CurrentDomain.GetAssemblies ();
260 foreach (Assembly ass in assemblies) {
261 type = ass.GetType (typeName);
262 if (type == null)
263 continue;
265 if (Path.GetDirectoryName (ass.Location) != PrivateBinPath) {
266 AddAssembly (ass, false);
267 } else {
268 seenBin = true;
271 AddDependency (ass.Location);
272 return type;
275 if (seenBin)
276 return null;
278 // Load from bin
279 if (!Directory.Exists (PrivateBinPath))
280 return null;
282 string [] binDlls = Directory.GetFiles (PrivateBinPath, "*.dll");
283 foreach (string s in binDlls) {
284 Assembly binA = Assembly.LoadFrom (s);
285 type = binA.GetType (typeName);
286 if (type == null)
287 continue;
289 AddDependency (binA.Location);
290 return type;
293 return null;
296 void AddAssembliesInBin ()
298 if (!Directory.Exists (PrivateBinPath))
299 return;
301 string [] binDlls = Directory.GetFiles (PrivateBinPath, "*.dll");
302 foreach (string s in binDlls) {
303 assemblies.Add (s);
307 internal virtual void AddInterface (string iface)
309 if (interfaces == null)
310 interfaces = new ArrayList ();
312 if (!interfaces.Contains (iface))
313 interfaces.Add (iface);
316 internal virtual void AddImport (string namesp)
318 if (imports == null)
319 imports = new ArrayList ();
321 if (!imports.Contains (namesp))
322 imports.Add (namesp);
325 internal virtual void AddDependency (string filename)
327 if (dependencies == null)
328 dependencies = new ArrayList ();
330 if (!dependencies.Contains (filename))
331 dependencies.Add (filename);
334 internal virtual void AddAssembly (Assembly assembly, bool fullPath)
336 if (anames == null)
337 anames = new Hashtable ();
339 string name = assembly.GetName ().Name;
340 string loc = assembly.Location;
341 if (fullPath) {
342 if (!assemblies.Contains (loc)) {
343 assemblies.Add (loc);
346 anames [name] = loc;
347 anames [loc] = assembly;
348 } else {
349 if (!assemblies.Contains (name)) {
350 assemblies.Add (name);
353 anames [name] = assembly;
357 internal virtual Assembly AddAssemblyByName (string name)
359 if (anames == null)
360 anames = new Hashtable ();
362 if (anames.Contains (name)) {
363 object o = anames [name];
364 if (o is string)
365 o = anames [o];
367 return (Assembly) o;
370 bool fullpath = false;
371 Assembly assembly = null;
372 try {
373 assembly = Assembly.LoadWithPartialName (name);
374 string loc = assembly.Location;
375 fullpath = (Path.GetDirectoryName (loc) == PrivateBinPath);
376 } catch (Exception e) {
377 ThrowParseException ("Assembly " + name + " not found", e);
380 AddAssembly (assembly, fullpath);
381 return assembly;
384 internal virtual void ProcessMainAttributes (Hashtable atts)
386 atts.Remove ("Description"); // ignored
387 atts.Remove ("CodeBehind"); // ignored
388 atts.Remove ("AspCompat"); // ignored
390 debug = GetBool (atts, "Debug", true);
391 compilerOptions = GetString (atts, "CompilerOptions", "");
392 language = GetString (atts, "Language", CompilationConfig.DefaultLanguage);
393 string src = GetString (atts, "Src", null);
394 if (src != null)
395 srcAssembly = GetAssemblyFromSource (src);
397 string inherits = GetString (atts, "Inherits", null);
398 if (inherits != null)
399 SetBaseType (inherits);
401 className = GetString (atts, "ClassName", null);
402 if (className != null && !CodeGenerator.IsValidLanguageIndependentIdentifier (className))
403 ThrowParseException (String.Format ("'{0}' is not valid for 'className'", className));
405 if (atts.Count > 0)
406 ThrowParseException ("Unknown attribute: " + GetOneKey (atts));
409 internal void SetBaseType (string type)
411 if (type == DefaultBaseTypeName)
412 return;
414 Type parent = null;
415 if (srcAssembly != null)
416 parent = srcAssembly.GetType (type);
418 if (parent == null)
419 parent = LoadType (type);
421 if (parent == null)
422 ThrowParseException ("Cannot find type " + type);
424 if (!DefaultBaseType.IsAssignableFrom (parent))
425 ThrowParseException ("The parent type does not derive from " + DefaultBaseType);
427 baseType = parent;
430 Assembly GetAssemblyFromSource (string vpath)
432 vpath = UrlUtils.Combine (BaseVirtualDir, vpath);
433 string realPath = MapPath (vpath, false);
434 if (!File.Exists (realPath))
435 ThrowParseException ("File " + vpath + " not found");
437 AddDependency (realPath);
439 CompilerResults result = CachingCompiler.Compile (language, realPath, realPath, assemblies);
440 if (result.NativeCompilerReturnValue != 0) {
441 StreamReader reader = new StreamReader (realPath);
442 throw new CompilationException (realPath, result.Errors, reader.ReadToEnd ());
445 AddAssembly (result.CompiledAssembly, true);
446 return result.CompiledAssembly;
449 internal abstract Type DefaultBaseType { get; }
450 internal abstract string DefaultBaseTypeName { get; }
451 internal abstract string DefaultDirectiveName { get; }
453 internal string InputFile
455 get { return inputFile; }
456 set { inputFile = value; }
459 internal string Text
461 get { return text; }
462 set { text = value; }
465 internal Type BaseType
467 get {
468 if (baseType == null)
469 baseType = DefaultBaseType;
471 return baseType;
475 internal string ClassName {
476 get {
477 if (className != null)
478 return className;
480 className = Path.GetFileName (inputFile).Replace ('.', '_');
481 className = className.Replace ('-', '_');
482 className = className.Replace (' ', '_');
484 if (Char.IsDigit(className[0])) {
485 className = "_" + className;
488 return className;
492 internal string PrivateBinPath {
493 get {
494 if (privateBinPath != null)
495 return privateBinPath;
497 AppDomainSetup setup = AppDomain.CurrentDomain.SetupInformation;
498 privateBinPath = Path.Combine (setup.ApplicationBase, setup.PrivateBinPath);
500 return privateBinPath;
504 internal ArrayList Scripts {
505 get {
506 if (scripts == null)
507 scripts = new ArrayList ();
509 return scripts;
513 internal ArrayList Imports {
514 get { return imports; }
517 internal ArrayList Assemblies {
518 get {
519 if (appAssemblyIndex != -1) {
520 object o = assemblies [appAssemblyIndex];
521 assemblies.RemoveAt (appAssemblyIndex);
522 assemblies.Add (o);
523 appAssemblyIndex = -1;
526 return assemblies;
530 internal ArrayList Interfaces {
531 get { return interfaces; }
534 internal RootBuilder RootBuilder {
535 get { return rootBuilder; }
536 set { rootBuilder = value; }
539 internal ArrayList Dependencies {
540 get { return dependencies; }
543 internal string CompilerOptions {
544 get { return compilerOptions; }
547 internal string Language {
548 get { return language; }
551 internal bool Debug {
552 get { return debug; }
555 internal bool OutputCache {
556 get { return output_cache; }
559 internal int OutputCacheDuration {
560 get { return oc_duration; }
563 internal string OutputCacheVaryByHeader {
564 get { return oc_header; }
567 internal string OutputCacheVaryByCustom {
568 get { return oc_custom; }
571 internal string OutputCacheVaryByControls {
572 get { return oc_controls; }
575 internal bool OutputCacheShared {
576 get { return oc_shared; }
579 internal OutputCacheLocation OutputCacheLocation {
580 get { return oc_location; }
583 internal string OutputCacheVaryByParam {
584 get { return oc_param; }
587 internal PagesConfiguration PagesConfig {
588 get { return PagesConfiguration.GetInstance (Context); }