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