2007-04-13 Marek Habersack <mhabersack@novell.com>
[mono.git] / mcs / class / System.Web / System.Web.UI / TemplateParser.cs
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 // Copyright (C) 2005 Novell, Inc (http://www.novell.com)
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30
31 using System.CodeDom.Compiler;
32 using System.Collections;
33 using System.ComponentModel;
34 using System.Globalization;
35 using System.IO;
36 using System.Reflection;
37 using System.Security.Permissions;
38 using System.Web.Compilation;
39 using System.Web.Configuration;
40 using System.Web.Util;
41
42 #if NET_2_0
43 using System.Collections.Generic;
44 #endif
45
46 namespace System.Web.UI {
47
48         // CAS
49         [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
50         [AspNetHostingPermission (SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
51         public abstract class TemplateParser : BaseParser
52         {
53                 string inputFile;
54                 string text;
55                 string privateBinPath;
56                 Hashtable mainAttributes;
57                 ArrayList dependencies;
58                 ArrayList assemblies;
59                 Hashtable anames;
60                 ArrayList imports;
61                 ArrayList interfaces;
62                 ArrayList scripts;
63                 Type baseType;
64                 bool baseTypeIsGlobal;
65                 string className;
66                 RootBuilder rootBuilder;
67                 bool debug;
68                 string compilerOptions;
69                 string language;
70                 bool strictOn = false;
71                 bool explicitOn = false;
72                 bool linePragmasOn = false;
73                 bool output_cache;
74                 int oc_duration;
75                 string oc_header, oc_custom, oc_param, oc_controls;
76                 bool oc_shared;
77                 OutputCacheLocation oc_location;
78                 CultureInfo invariantCulture = CultureInfo.InvariantCulture;
79 #if NET_2_0
80                 string src;
81                 string partialClassName;
82                 string codeFileBaseClass;
83                 string metaResourceKey;
84                 Type codeFileBaseClassType;
85                 List <UnknownAttributeDescriptor> unknownMainAttributes;
86 #endif
87                 Assembly srcAssembly;
88                 int appAssemblyIndex = -1;
89
90                 internal TemplateParser ()
91                 {
92                         imports = new ArrayList ();
93 #if NET_2_0
94                         AddNamespaces (imports);
95 #else
96                         imports.Add ("System");
97                         imports.Add ("System.Collections");
98                         imports.Add ("System.Collections.Specialized");
99                         imports.Add ("System.Configuration");
100                         imports.Add ("System.Text");
101                         imports.Add ("System.Text.RegularExpressions");
102                         imports.Add ("System.Web");
103                         imports.Add ("System.Web.Caching");
104                         imports.Add ("System.Web.Security");
105                         imports.Add ("System.Web.SessionState");
106                         imports.Add ("System.Web.UI");
107                         imports.Add ("System.Web.UI.WebControls");
108                         imports.Add ("System.Web.UI.HtmlControls");
109 #endif
110
111                         assemblies = new ArrayList ();
112 #if NET_2_0
113                         bool addAssembliesInBin = false;
114                         foreach (AssemblyInfo info in CompilationConfig.Assemblies) {
115                                 if (info.Assembly == "*")
116                                         addAssembliesInBin = true;
117                                 else
118                                         AddAssemblyByName (info.Assembly);
119                         }
120                         if (addAssembliesInBin)
121                                 AddAssembliesInBin ();
122
123                         foreach (NamespaceInfo info in PagesConfig.Namespaces) {
124                                 imports.Add (info.Namespace);
125                         }
126 #else
127                         foreach (string a in CompilationConfig.Assemblies)
128                                 AddAssemblyByName (a);
129                         if (CompilationConfig.AssembliesInBin)
130                                 AddAssembliesInBin ();
131 #endif
132
133                         language = CompilationConfig.DefaultLanguage;
134                 }
135                 
136                 internal void AddApplicationAssembly ()
137                 {
138                         if (Context.ApplicationInstance == null)
139                                 return; // this may happen if we have Global.asax and have
140                                         // controls registered from Web.Config
141                         string location = Context.ApplicationInstance.AssemblyLocation;
142                         if (location != typeof (TemplateParser).Assembly.Location) {
143                                 appAssemblyIndex = assemblies.Add (location);
144                         }
145                 }
146
147                 protected abstract Type CompileIntoType ();
148
149 #if NET_2_0
150                 void AddNamespaces (ArrayList imports)
151                 {
152                         if (BuildManager.HaveResources)
153                                 imports.Add ("System.Resources");
154                         
155                         PagesSection pages = WebConfigurationManager.GetSection ("system.web/pages") as PagesSection;
156                         if (pages == null)
157                                 return;
158
159                         NamespaceCollection namespaces = pages.Namespaces;
160                         if (namespaces == null || namespaces.Count == 0)
161                                 return;
162
163                         foreach (NamespaceInfo nsi in namespaces)
164                                 imports.Add (nsi.Namespace);
165                 }
166 #endif
167                 
168                 internal void RegisterCustomControl (string tagPrefix, string tagName, string src)
169                 {
170                         string realpath = MapPath (src);
171                         if (String.Compare (realpath, inputFile, false, invariantCulture) == 0)
172                                 return;
173                         
174                         if (!File.Exists (realpath))
175                                 throw new ParseException (Location, "Could not find file \"" + realpath + "\".");
176                         string vpath = UrlUtils.Combine (BaseVirtualDir, src);
177                         Type type = null;
178                         AddDependency (realpath);
179                         try {
180                                 ArrayList other_deps = new ArrayList ();
181                                 type = UserControlParser.GetCompiledType (vpath, realpath, other_deps, Context);
182                                 foreach (string s in other_deps) {
183                                         AddDependency (s);
184                                 }
185                         } catch (ParseException pe) {
186                                 if (this is UserControlParser)
187                                         throw new ParseException (Location, pe.Message, pe);
188                                 throw;
189                         }
190
191                         AddAssembly (type.Assembly, true);
192                         RootBuilder.Foundry.RegisterFoundry (tagPrefix, tagName, type);
193                 }
194
195                 internal void RegisterNamespace (string tagPrefix, string ns, string assembly)
196                 {
197                         AddImport (ns);
198                         Assembly ass = AddAssemblyByName (assembly);
199                         AddDependency (ass.Location);
200                         RootBuilder.Foundry.RegisterFoundry (tagPrefix, ass, ns);
201                 }
202
203                 internal virtual void HandleOptions (object obj)
204                 {
205                 }
206
207                 internal static string GetOneKey (Hashtable tbl)
208                 {
209                         foreach (object key in tbl.Keys)
210                                 return key.ToString ();
211
212                         return null;
213                 }
214                 
215                 internal virtual void AddDirective (string directive, Hashtable atts)
216                 {
217                         if (String.Compare (directive, DefaultDirectiveName, true) == 0) {
218                                 if (mainAttributes != null)
219                                         ThrowParseException ("Only 1 " + DefaultDirectiveName + " is allowed");
220
221                                 mainAttributes = atts;
222                                 ProcessMainAttributes (mainAttributes);
223                                 return;
224                         }
225
226                         int cmp = String.Compare ("Assembly", directive, true);
227                         if (cmp == 0) {
228                                 string name = GetString (atts, "Name", null);
229                                 string src = GetString (atts, "Src", null);
230
231                                 if (atts.Count > 0)
232                                         ThrowParseException ("Attribute " + GetOneKey (atts) + " unknown.");
233
234                                 if (name == null && src == null)
235                                         ThrowParseException ("You gotta specify Src or Name");
236                                         
237                                 if (name != null && src != null)
238                                         ThrowParseException ("Src and Name cannot be used together");
239
240                                 if (name != null) {
241                                         AddAssemblyByName (name);
242                                 } else {
243                                         GetAssemblyFromSource (src);
244                                 }
245
246                                 return;
247                         }
248
249                         cmp = String.Compare ("Import", directive, true);
250                         if (cmp == 0) {
251                                 string namesp = GetString (atts, "Namespace", null);
252                                 if (atts.Count > 0)
253                                         ThrowParseException ("Attribute " + GetOneKey (atts) + " unknown.");
254                                 
255                                 if (namesp != null && namesp != "")
256                                         AddImport (namesp);
257                                 return;
258                         }
259
260                         cmp = String.Compare ("Implements", directive, true);
261                         if (cmp == 0) {
262                                 string ifacename = GetString (atts, "Interface", "");
263
264                                 if (atts.Count > 0)
265                                         ThrowParseException ("Attribute " + GetOneKey (atts) + " unknown.");
266                                 
267                                 Type iface = LoadType (ifacename);
268                                 if (iface == null)
269                                         ThrowParseException ("Cannot find type " + ifacename);
270
271                                 if (!iface.IsInterface)
272                                         ThrowParseException (iface + " is not an interface");
273
274                                 AddInterface (iface.FullName);
275                                 return;
276                         }
277
278                         cmp = String.Compare ("OutputCache", directive, true);
279                         if (cmp == 0) {
280                                 HttpResponse response = HttpContext.Current.Response;
281                                 if (response != null)
282                                         response.Cache.SetValidUntilExpires (true);
283                                 
284                                 output_cache = true;
285                                 
286                                 if (atts ["Duration"] == null)
287                                         ThrowParseException ("The directive is missing a 'duration' attribute.");
288                                 if (atts ["VaryByParam"] == null)
289                                         ThrowParseException ("This directive is missing a 'VaryByParam' " +
290                                                         "attribute, which should be set to \"none\", \"*\", " +
291                                                         "or a list of name/value pairs.");
292
293                                 foreach (DictionaryEntry entry in atts) {
294                                         string key = (string) entry.Key;
295                                         switch (key.ToLower ()) {
296                                         case "duration":
297                                                 oc_duration = Int32.Parse ((string) entry.Value);
298                                                 if (oc_duration < 1)
299                                                         ThrowParseException ("The 'duration' attribute must be set " +
300                                                                         "to a positive integer value");
301                                                 break;
302                                         case "varybyparam":
303                                                 oc_param = (string) entry.Value;
304                                                 if (String.Compare (oc_param, "none") == 0)
305                                                         oc_param = null;
306                                                 break;
307                                         case "varybyheader":
308                                                 oc_header = (string) entry.Value;
309                                                 break;
310                                         case "varybycustom":
311                                                 oc_custom = (string) entry.Value;
312                                                 break;
313                                         case "location":
314                                                 if (!(this is PageParser))
315                                                         goto default;
316
317                                                 try {
318                                                         oc_location = (OutputCacheLocation) Enum.Parse (
319                                                                 typeof (OutputCacheLocation), (string) entry.Value, true);
320                                                 } catch {
321                                                         ThrowParseException ("The 'location' attribute is case sensitive and " +
322                                                                         "must be one of the following values: Any, Client, " +
323                                                                         "Downstream, Server, None, ServerAndClient.");
324                                                 }
325                                                 break;
326                                         case "varybycontrol":
327                                                 if (this is PageParser)
328                                                         goto default;
329
330                                                 oc_controls = (string) entry.Value;
331                                                 break;
332                                         case "shared":
333                                                 if (this is PageParser)
334                                                         goto default;
335
336                                                 try {
337                                                         oc_shared = Boolean.Parse ((string) entry.Value);
338                                                 } catch {
339                                                         ThrowParseException ("The 'shared' attribute is case sensitive" +
340                                                                         " and must be set to 'true' or 'false'.");
341                                                 }
342                                                 break;
343                                         default:
344                                                 ThrowParseException ("The '" + key + "' attribute is not " +
345                                                                 "supported by the 'Outputcache' directive.");
346                                                 break;
347                                         }
348                                         
349                                 }
350                                 
351                                 return;
352                         }
353
354                         ThrowParseException ("Unknown directive: " + directive);
355                 }
356
357                 internal Type LoadType (string typeName)
358                 {
359                         // First try loaded assemblies, then try assemblies in Bin directory.
360                         Type type = null;
361                         bool seenBin = false;
362                         Assembly [] assemblies = AppDomain.CurrentDomain.GetAssemblies ();
363                         foreach (Assembly ass in assemblies) {
364                                 type = ass.GetType (typeName);
365                                 if (type == null)
366                                         continue;
367
368                                 if (Path.GetDirectoryName (ass.Location) != PrivateBinPath) {
369                                         AddAssembly (ass, true);
370                                 } else {
371                                         seenBin = true;
372                                 }
373
374                                 AddDependency (ass.Location);
375                                 return type;
376                         }
377
378                         if (seenBin)
379                                 return null;
380
381                         // Load from bin
382                         if (!Directory.Exists (PrivateBinPath))
383                                 return null;
384
385                         string [] binDlls = Directory.GetFiles (PrivateBinPath, "*.dll");
386                         foreach (string s in binDlls) {
387                                 Assembly binA = Assembly.LoadFrom (s);
388                                 type = binA.GetType (typeName);
389                                 if (type == null)
390                                         continue;
391
392                                 AddDependency (binA.Location);
393                                 return type;
394                         }
395
396                         return null;
397                 }
398
399                 void AddAssembliesInBin ()
400                 {
401                         if (!Directory.Exists (PrivateBinPath))
402                                 return;
403
404                         string [] binDlls = Directory.GetFiles (PrivateBinPath, "*.dll");
405                         foreach (string s in binDlls)
406                                 assemblies.Add (s);
407                 }
408
409                 internal virtual void AddInterface (string iface)
410                 {
411                         if (interfaces == null)
412                                 interfaces = new ArrayList ();
413
414                         if (!interfaces.Contains (iface))
415                                 interfaces.Add (iface);
416                 }
417                 
418                 internal virtual void AddImport (string namesp)
419                 {
420                         if (imports == null)
421                                 imports = new ArrayList ();
422
423                         if (!imports.Contains (namesp))
424                                 imports.Add (namesp);
425                 }
426
427                 internal virtual void AddSourceDependency (string filename)
428                 {
429                         if (dependencies != null && dependencies.Contains (filename)) {
430                                 ThrowParseException ("Circular file references are not allowed. File: " + filename);
431                         }
432
433                         AddDependency (filename);
434                 }
435
436                 internal virtual void AddDependency (string filename)
437                 {
438                         if (filename == "")
439                                 return;
440
441                         if (dependencies == null)
442                                 dependencies = new ArrayList ();
443
444                         if (!dependencies.Contains (filename))
445                                 dependencies.Add (filename);
446                 }
447                 
448                 internal virtual void AddAssembly (Assembly assembly, bool fullPath)
449                 {
450                         if (assembly.Location == "")
451                                 return;
452
453                         if (anames == null)
454                                 anames = new Hashtable ();
455
456                         string name = assembly.GetName ().Name;
457                         string loc = assembly.Location;
458                         if (fullPath) {
459                                 if (!assemblies.Contains (loc)) {
460                                         assemblies.Add (loc);
461                                 }
462
463                                 anames [name] = loc;
464                                 anames [loc] = assembly;
465                         } else {
466                                 if (!assemblies.Contains (name)) {
467                                         assemblies.Add (name);
468                                 }
469
470                                 anames [name] = assembly;
471                         }
472                 }
473
474                 internal virtual Assembly AddAssemblyByFileName (string filename)
475                 {
476                         Assembly assembly = null;
477                         Exception error = null;
478
479                         try {
480                                 assembly = Assembly.LoadFrom (filename);
481                         } catch (Exception e) { error = e; }
482
483                         if (assembly == null)
484                                 ThrowParseException ("Assembly " + filename + " not found", error);
485
486                         AddAssembly (assembly, true);
487                         return assembly;
488                 }
489
490                 internal virtual Assembly AddAssemblyByName (string name)
491                 {
492                         if (anames == null)
493                                 anames = new Hashtable ();
494
495                         if (anames.Contains (name)) {
496                                 object o = anames [name];
497                                 if (o is string)
498                                         o = anames [o];
499
500                                 return (Assembly) o;
501                         }
502
503                         Assembly assembly = null;
504                         Exception error = null;
505                         if (name.IndexOf (',') != -1) {
506                                 try {
507                                         assembly = Assembly.Load (name);
508                                 } catch (Exception e) { error = e; }
509                         }
510
511                         if (assembly == null) {
512                                 try {
513                                         assembly = Assembly.LoadWithPartialName (name);
514                                 } catch (Exception e) { error = e; }
515                         }
516                         
517                         if (assembly == null)
518                                 ThrowParseException ("Assembly " + name + " not found", error);
519
520                         AddAssembly (assembly, true);
521                         return assembly;
522                 }
523                 
524                 internal virtual void ProcessMainAttributes (Hashtable atts)
525                 {
526                         atts.Remove ("Description"); // ignored
527 #if NET_1_1
528                         atts.Remove ("CodeBehind");  // ignored
529 #endif
530                         atts.Remove ("AspCompat"); // ignored
531 #if NET_2_0
532                         // these two are ignored for the moment
533                         atts.Remove ("Async");
534                         atts.Remove ("AsyncTimeOut");
535 #endif
536                         
537                         debug = GetBool (atts, "Debug", true);
538                         compilerOptions = GetString (atts, "CompilerOptions", "");
539                         language = GetString (atts, "Language", CompilationConfig.DefaultLanguage);
540                         strictOn = GetBool (atts, "Strict", CompilationConfig.Strict);
541                         explicitOn = GetBool (atts, "Explicit", CompilationConfig.Explicit);
542                         linePragmasOn = GetBool (atts, "LinePragmas", false);
543                         
544                         string inherits = GetString (atts, "Inherits", null);
545 #if NET_2_0
546                         // In ASP 2, the source file is actually integrated with
547                         // the generated file via the use of partial classes. This
548                         // means that the code file has to be confirmed, but not
549                         // used at this point.
550                         src = GetString (atts, "CodeFile", null);
551                         codeFileBaseClass = GetString (atts, "CodeFileBaseClass", null);
552
553                         if (src == null && codeFileBaseClass != null)
554                                 ThrowParseException ("The 'CodeFileBaseClass' attribute cannot be used without a 'CodeFile' attribute");
555                         
556                         if (src != null && inherits != null) {
557                                 // Make sure the source exists
558                                 src = UrlUtils.Combine (BaseVirtualDir, src);
559                                 string realPath = MapPath (src, false);
560                                 if (!File.Exists (realPath))
561                                         ThrowParseException ("File " + src + " not found");
562
563                                 // We are going to create a partial class that shares
564                                 // the same name as the inherits tag, so reset the
565                                 // name. The base type is changed because it is the
566                                 // code file's responsibilty to extend the classes
567                                 // needed.
568                                 partialClassName = inherits;
569
570                                 // Add the code file as an option to the
571                                 // compiler. This lets both files be compiled at once.
572                                 compilerOptions += " \"" + realPath + "\"";
573
574                                 if (codeFileBaseClass != null) {
575                                         try {
576                                                 codeFileBaseClassType = LoadType (codeFileBaseClass);
577                                         } catch (Exception) {
578                                         }
579
580                                         if (codeFileBaseClassType == null)
581                                                 ThrowParseException ("Could not load type '{0}'", codeFileBaseClass);
582                                 }
583                         } else if (inherits != null) {
584                                 // We just set the inherits directly because this is a
585                                 // Single-Page model.
586                                 SetBaseType (inherits);
587                         }
588 #else
589                         string src = GetString (atts, "Src", null);
590
591                         if (src != null)
592                                 srcAssembly = GetAssemblyFromSource (src);
593
594                         if (inherits != null)
595                                 SetBaseType (inherits);
596 #endif
597                         className = GetString (atts, "ClassName", null);
598                         if (className != null && !CodeGenerator.IsValidLanguageIndependentIdentifier (className))
599                                 ThrowParseException (String.Format ("'{0}' is not valid for 'className'", className));
600
601 #if NET_2_0
602                         if (this is TemplateControlParser)
603                                 metaResourceKey = GetString (atts, "meta:resourcekey", null);
604                         
605                         if (inherits != null && (this is PageParser || this is UserControlParser) && atts.Count > 0) {
606                                 if (unknownMainAttributes == null)
607                                         unknownMainAttributes = new List <UnknownAttributeDescriptor> ();
608                                 string key, val;
609                                 
610                                 foreach (DictionaryEntry de in atts) {
611                                         key = de.Key as string;
612                                         val = de.Value as string;
613                                         
614                                         if (String.IsNullOrEmpty (key) || String.IsNullOrEmpty (val))
615                                                 continue;
616                                         CheckUnknownAttribute (key, val, inherits);
617                                 }
618                                 return;
619                         }
620 #endif
621                         if (atts.Count > 0)
622                                 ThrowParseException ("Unknown attribute: " + GetOneKey (atts));
623                 }
624
625 #if NET_2_0
626                 void CheckUnknownAttribute (string name, string val, string inherits)
627                 {
628                         MemberInfo mi = null;
629                         bool missing = false;
630                         string memberName = name.Trim ().ToLower (CultureInfo.InvariantCulture);
631                         Type parent = codeFileBaseClassType;
632
633                         if (parent == null)
634                                 parent = baseType;
635                         
636                         try {
637                                 MemberInfo[] infos = parent.GetMember (memberName,
638                                                                        MemberTypes.Field | MemberTypes.Property,
639                                                                        BindingFlags.Public | BindingFlags.Instance |
640                                                                        BindingFlags.IgnoreCase | BindingFlags.Static);
641                                 if (infos.Length != 0) {
642                                         // prefer public properties to public methods (it's what MS.NET does)
643                                         foreach (MemberInfo tmp in infos) {
644                                                 if (tmp is PropertyInfo) {
645                                                         mi = tmp;
646                                                         break;
647                                                 }
648                                         }
649                                         if (mi == null)
650                                                 mi = infos [0];
651                                 } else
652                                         missing = true;
653                         } catch (Exception) {
654                                 missing = true;
655                         }
656                         if (missing)
657                                 ThrowParseException (
658                                         "Error parsing attribute '{0}': Type '{1}' does not have a public property named '{0}'",
659                                         memberName, inherits);
660                         
661                         Type memberType = null;
662                         if (mi is PropertyInfo) {
663                                 PropertyInfo pi = mi as PropertyInfo;
664                                 
665                                 if (!pi.CanWrite)
666                                         ThrowParseException (
667                                                 "Error parsing attribute '{0}': The '{0}' property is read-only and cannot be set.",
668                                                 memberName);
669                                 memberType = pi.PropertyType;
670                         } else if (mi is FieldInfo) {
671                                 memberType = ((FieldInfo)mi).FieldType;
672                         } else
673                                 ThrowParseException ("Could not determine member the kind of '{0}' in base type '{1}",
674                                                      memberName, inherits);
675                         TypeConverter converter = TypeDescriptor.GetConverter (memberType);
676                         bool convertible = true;
677                         object value = null;
678                         
679                         if (converter == null || !converter.CanConvertFrom (typeof (string)))
680                                 convertible = false;
681
682                         if (convertible) {
683                                 try {
684                                         value = converter.ConvertFromInvariantString (val);
685                                 } catch (Exception) {
686                                         convertible = false;
687                                 }
688                         }
689
690                         if (!convertible)
691                                 ThrowParseException ("Error parsing attribute '{0}': Cannot create an object of type '{1}' from its string representation '{2}' for the '{3}' property.",
692                                                      memberName, memberType, val, mi.Name);
693                         
694                         UnknownAttributeDescriptor desc = new UnknownAttributeDescriptor (mi, value);
695                         unknownMainAttributes.Add (desc);
696                 }
697 #endif
698                 
699                 internal void SetBaseType (string type)
700                 {
701                         if (type == DefaultBaseTypeName)
702                                 return;
703
704                         Type parent = null;
705                         if (srcAssembly != null)
706                                 parent = srcAssembly.GetType (type);
707
708                         if (parent == null)
709                                 parent = LoadType (type);
710
711                         if (parent == null)
712                                 ThrowParseException ("Cannot find type " + type);
713
714                         if (!DefaultBaseType.IsAssignableFrom (parent))
715                                 ThrowParseException ("The parent type does not derive from " + DefaultBaseType);
716
717                         baseType = parent;
718                         if (parent.FullName.IndexOf ('.') == -1)
719                                 baseTypeIsGlobal = true;
720                 }
721
722                 Assembly GetAssemblyFromSource (string vpath)
723                 {
724                         vpath = UrlUtils.Combine (BaseVirtualDir, vpath);
725                         string realPath = MapPath (vpath, false);
726                         if (!File.Exists (realPath))
727                                 ThrowParseException ("File " + vpath + " not found");
728
729                         AddSourceDependency (realPath);
730
731                         CompilerResults result = CachingCompiler.Compile (language, realPath, realPath, assemblies);
732                         if (result.NativeCompilerReturnValue != 0) {
733                                 StreamReader reader = new StreamReader (realPath);
734                                 throw new CompilationException (realPath, result.Errors, reader.ReadToEnd ());
735                         }
736
737                         AddAssembly (result.CompiledAssembly, true);
738                         return result.CompiledAssembly;
739                 }
740                 
741                 internal abstract Type DefaultBaseType { get; }
742                 internal abstract string DefaultBaseTypeName { get; }
743                 internal abstract string DefaultDirectiveName { get; }
744
745                 internal string InputFile
746                 {
747                         get { return inputFile; }
748                         set { inputFile = value; }
749                 }
750
751 #if NET_2_0
752                 internal bool IsPartial {
753                         get { return src != null; }
754                 }
755
756                 internal string PartialClassName {
757                         get { return partialClassName; }
758                 }
759
760                 internal string CodeFileBaseClass {
761                         get { return codeFileBaseClass; }
762                 }
763
764                 internal string MetaResourceKey {
765                         get { return metaResourceKey; }
766                 }
767                 
768                 internal Type CodeFileBaseClassType
769                 {
770                         get { return codeFileBaseClassType; }
771                 }
772                 
773                 internal List <UnknownAttributeDescriptor> UnknownMainAttributes
774                 {
775                         get { return unknownMainAttributes; }
776                 }
777 #endif
778
779                 internal string Text
780                 {
781                         get { return text; }
782                         set { text = value; }
783                 }
784
785                 internal Type BaseType
786                 {
787                         get {
788                                 if (baseType == null)
789                                         baseType = DefaultBaseType;
790
791                                 return baseType;
792                         }
793                 }
794                 
795                 internal bool BaseTypeIsGlobal {
796                         get { return baseTypeIsGlobal; }
797                 }
798                 
799                 internal string ClassName {
800                         get {
801                                 if (className != null)
802                                         return className;
803
804 #if NET_2_0
805                                 string physPath = HttpContext.Current.Request.PhysicalApplicationPath;
806                                 
807                                 if (StrUtils.StartsWith (inputFile, physPath)) {
808                                         className = inputFile.Substring (physPath.Length).ToLower (CultureInfo.InvariantCulture);
809                                         className = className.Replace ('.', '_');
810                                         className = className.Replace ('/', '_').Replace ('\\', '_');
811                                 } else
812 #endif
813                                 className = Path.GetFileName (inputFile).Replace ('.', '_');
814                                 className = className.Replace ('-', '_'); 
815                                 className = className.Replace (' ', '_');
816
817                                 if (Char.IsDigit(className[0])) {
818                                         className = "_" + className;
819                                 }
820
821                                 return className;
822                         }
823                 }
824
825                 internal string PrivateBinPath {
826                         get {
827                                 if (privateBinPath != null)
828                                         return privateBinPath;
829
830                                 AppDomainSetup setup = AppDomain.CurrentDomain.SetupInformation;
831                                 privateBinPath = Path.Combine (setup.ApplicationBase, setup.PrivateBinPath);
832
833                                 return privateBinPath;
834                         }
835                 }
836
837                 internal ArrayList Scripts {
838                         get {
839                                 if (scripts == null)
840                                         scripts = new ArrayList ();
841
842                                 return scripts;
843                         }
844                 }
845
846                 internal ArrayList Imports {
847                         get { return imports; }
848                 }
849
850                 internal ArrayList Assemblies {
851                         get {
852                                 if (appAssemblyIndex != -1) {
853                                         object o = assemblies [appAssemblyIndex];
854                                         assemblies.RemoveAt (appAssemblyIndex);
855                                         assemblies.Add (o);
856                                         appAssemblyIndex = -1;
857                                 }
858
859                                 return assemblies;
860                         }
861                 }
862
863                 internal ArrayList Interfaces {
864                         get { return interfaces; }
865                 }
866
867                 internal RootBuilder RootBuilder {
868                         get { return rootBuilder; }
869                         set { rootBuilder = value; }
870                 }
871
872                 internal ArrayList Dependencies {
873                         get { return dependencies; }
874                         set { dependencies = value; }
875                 }
876
877                 internal string CompilerOptions {
878                         get { return compilerOptions; }
879                 }
880
881                 internal string Language {
882                         get { return language; }
883                 }
884
885                 internal bool StrictOn {
886                         get { return strictOn; }
887                 }
888
889                 internal bool ExplicitOn {
890                         get { return explicitOn; }
891                 }
892                 
893                 internal bool Debug {
894                         get { return debug; }
895                 }
896
897                 internal bool OutputCache {
898                         get { return output_cache; }
899                 }
900
901                 internal int OutputCacheDuration {
902                         get { return oc_duration; }
903                 }
904
905                 internal string OutputCacheVaryByHeader {
906                         get { return oc_header; }
907                 }
908
909                 internal string OutputCacheVaryByCustom {
910                         get { return oc_custom; }
911                 }
912
913                 internal string OutputCacheVaryByControls {
914                         get { return oc_controls; }
915                 }
916                 
917                 internal bool OutputCacheShared {
918                         get { return oc_shared; }
919                 }
920                 
921                 internal OutputCacheLocation OutputCacheLocation {
922                         get { return oc_location; }
923                 }
924
925                 internal string OutputCacheVaryByParam {
926                         get { return oc_param; }
927                 }
928
929 #if NET_2_0
930                 internal PagesSection PagesConfig {
931                         get {
932                                 return WebConfigurationManager.GetSection ("system.web/pages") as PagesSection;
933                         }
934                 }
935 #else
936                 internal PagesConfiguration PagesConfig {
937                         get { return PagesConfiguration.GetInstance (Context); }
938                 }
939 #endif
940         }
941 }
942