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