2009-05-04 Marek Habersack <mhabersack@novell.com>
[mono.git] / mcs / class / System.Web / System.Web.Compilation / TemplateBuildProvider.cs
1 //
2 // System.Web.Compilation.TemplateBuildProvider
3 //
4 // Authors:
5 //   Marek Habersack (mhabersack@novell.com)
6 //
7 // (C) 2007 Novell, Inc
8 //
9
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 #if NET_2_0
31 using System;
32 using System.CodeDom;
33 using System.CodeDom.Compiler;
34 using System.Collections;
35 using System.Collections.Generic;
36 using System.IO;
37 using System.Reflection;
38 using System.Text.RegularExpressions;
39 using System.Web;
40 using System.Web.Hosting;
41 using System.Web.UI;
42 using System.Web.Util;
43
44 namespace System.Web.Compilation
45 {
46         internal abstract class TemplateBuildProvider : GenericBuildProvider <TemplateParser>
47         {
48                 delegate void ExtractDirectiveDependencies (string baseDirectory, CaptureCollection names, CaptureCollection values, TemplateBuildProvider bp);
49                 
50                 static SortedDictionary <string, ExtractDirectiveDependencies> directiveAttributes;
51                 static char[] directiveValueTrimChars = {' ', '\t', '\r', '\n', '"', '\''};
52
53                 SortedDictionary <string, bool> dependencies;
54                 string compilationLanguage;
55                 
56                 internal override string LanguageName {
57                         get {
58                                 if (String.IsNullOrEmpty (compilationLanguage)) {
59                                         ExtractDependencies ();
60                                         if (String.IsNullOrEmpty (compilationLanguage))
61                                                 compilationLanguage = base.LanguageName;
62                                 }
63                                 
64                                 return compilationLanguage;
65                         }
66                 }
67                 
68                 static TemplateBuildProvider ()
69                 {
70                         directiveAttributes = new SortedDictionary <string, ExtractDirectiveDependencies> (StringComparer.InvariantCultureIgnoreCase);
71                         directiveAttributes.Add ("Control", ExtractControlDependencies);
72                         directiveAttributes.Add ("Master", ExtractPageOrMasterDependencies);
73                         directiveAttributes.Add ("MasterType", ExtractPreviousPageTypeOrMasterTypeDependencies);
74                         directiveAttributes.Add ("Page", ExtractPageOrMasterDependencies);
75                         directiveAttributes.Add ("PreviousPageType", ExtractPreviousPageTypeOrMasterTypeDependencies);
76                         directiveAttributes.Add ("Reference", ExtractReferenceDependencies);
77                         directiveAttributes.Add ("Register", ExtractRegisterDependencies);
78                         directiveAttributes.Add ("WebHandler", ExtractLanguage);
79                         directiveAttributes.Add ("WebService", ExtractLanguage);
80                 }
81
82                 static string ExtractDirectiveAttribute (string baseDirectory, string name, CaptureCollection names, CaptureCollection values)
83                 {
84                         return ExtractDirectiveAttribute (baseDirectory, name, names, values, true);
85                 }
86                 
87                 static string ExtractDirectiveAttribute (string baseDirectory, string name, CaptureCollection names, CaptureCollection values, bool isPath)
88                 {
89                         if (names.Count == 0)
90                                 return String.Empty;
91
92                         int index = 0;
93                         int valuesCount = values.Count;
94                         foreach (Capture c in names) {
95                                 if (String.Compare (c.Value, name, StringComparison.OrdinalIgnoreCase) != 0) {
96                                         index++;
97                                         continue;
98                                 }
99                                 
100                                 if (index > valuesCount)
101                                         return String.Empty;
102
103                                 if (isPath)
104                                         return new VirtualPath (values [index].Value.Trim (directiveValueTrimChars), baseDirectory).Absolute;
105                                 else
106                                         return values [index].Value.Trim ();
107                         }
108
109                         return String.Empty;
110                 }
111
112                 static void ExtractControlDependencies (string baseDirectory, CaptureCollection names, CaptureCollection values, TemplateBuildProvider bp)
113                 {
114                         ExtractLanguage (baseDirectory, names, values, bp);
115                         ExtractCodeBehind (baseDirectory, names, values, bp);
116                 }
117                 
118                 static void ExtractLanguage (string baseDirectory, CaptureCollection names, CaptureCollection values, TemplateBuildProvider bp)
119                 {
120                         string value = ExtractDirectiveAttribute (baseDirectory, "Language", names, values, false);
121                         if (String.IsNullOrEmpty (value))
122                                 return;
123
124                         bp.compilationLanguage = value;
125
126                         ExtractCodeBehind (baseDirectory, names, values, bp);
127                 }
128                 
129                 static void ExtractPageOrMasterDependencies (string baseDirectory, CaptureCollection names, CaptureCollection values, TemplateBuildProvider bp)
130                 {
131                         ExtractLanguage (baseDirectory, names, values, bp);
132                         string value = ExtractDirectiveAttribute (baseDirectory, "MasterPageFile", names, values);
133                         if (!String.IsNullOrEmpty (value)) {
134                                 if (!bp.dependencies.ContainsKey (value))
135                                         bp.dependencies.Add (value, true);
136                         }
137
138                         ExtractCodeBehind (baseDirectory, names, values, bp);
139                 }
140
141                 static void ExtractCodeBehind (string baseDirectory, CaptureCollection names, CaptureCollection values, TemplateBuildProvider bp)
142                 {
143                         string[] varray = new string [2];
144
145                         varray [0] = ExtractDirectiveAttribute (baseDirectory, "CodeFile", names, values);
146                         varray [1] = ExtractDirectiveAttribute (baseDirectory, "Src", names, values);
147                         foreach (string value in varray) {
148                                 if (!String.IsNullOrEmpty (value)) {
149                                         if (!bp.dependencies.ContainsKey (value))
150                                                 bp.dependencies.Add (value, true);
151                                 }
152                         }
153                 }
154                 
155                 static void ExtractRegisterDependencies (string baseDirectory, CaptureCollection names, CaptureCollection values, TemplateBuildProvider bp)
156                 {
157                         string src = ExtractDirectiveAttribute (baseDirectory, "Src", names, values);
158                         if (String.IsNullOrEmpty (src))
159                                 return;
160                         
161                         string value = ExtractDirectiveAttribute (baseDirectory, "TagName", names, values);
162                         if (String.IsNullOrEmpty (value))
163                                 return;
164
165                         value = ExtractDirectiveAttribute (baseDirectory, "TagPrefix", names, values);
166                         if (String.IsNullOrEmpty (value))
167                                 return;
168
169                         if (bp.dependencies.ContainsKey (src))
170                                 return;
171
172                         bp.dependencies.Add (src, true);
173                 }
174
175                 static void ExtractPreviousPageTypeOrMasterTypeDependencies (string baseDirectory, CaptureCollection names, CaptureCollection values, TemplateBuildProvider bp)
176                 {
177                         string value = ExtractDirectiveAttribute (baseDirectory, "VirtualPath", names, values);
178                         if (String.IsNullOrEmpty (value))
179                                 return;
180
181                         if (bp.dependencies.ContainsKey (value))
182                                 return;
183
184                         bp.dependencies.Add (value, true);
185                 }
186
187                 static void ExtractReferenceDependencies (string baseDirectory, CaptureCollection names, CaptureCollection values, TemplateBuildProvider bp)
188                 {
189                         string control = ExtractDirectiveAttribute (baseDirectory, "Control", names, values);
190                         string virtualPath = ExtractDirectiveAttribute (baseDirectory, "VirtualPath", names, values);
191                         string page = ExtractDirectiveAttribute (baseDirectory, "Page", names, values);
192                         bool controlEmpty = String.IsNullOrEmpty (control);
193                         bool virtualPathEmpty = String.IsNullOrEmpty (virtualPath);
194                         bool pageEmpty = String.IsNullOrEmpty (page);
195                         
196                         if (controlEmpty && virtualPathEmpty && pageEmpty)
197                                 return;
198
199                         if ((controlEmpty ? 1 : 0) + (virtualPathEmpty ? 1 : 0) + (pageEmpty ? 1 : 0) != 2)
200                                 return;
201                         
202                         string value;
203                         if (!controlEmpty)
204                                 value = control;
205                         else if (!virtualPathEmpty)
206                                 value = virtualPath;
207                         else
208                                 value = page;
209
210                         if (bp.dependencies.ContainsKey (value))
211                                 return;
212
213                         bp.dependencies.Add (value, true);
214                 }
215                 
216                 internal override IDictionary <string, bool> ExtractDependencies ()
217                 {
218                         if (dependencies != null) {
219                                 if (dependencies.Count == 0)
220                                         return null;
221                                 return dependencies;
222                         }
223
224                         string vpath = VirtualPath;
225                         if (String.IsNullOrEmpty (vpath))
226                                 return null;
227
228                         VirtualPathProvider vpp = HostingEnvironment.VirtualPathProvider;
229                         if (!vpp.FileExists (vpath))
230                                 return null;
231                         
232                         VirtualFile vf = vpp.GetFile (vpath);
233                         if (vf == null)
234                                 return null;
235
236                         string input;
237                         using (Stream st = vf.Open ()) {
238                                 if (st == null || !st.CanRead)
239                                         return null;
240                                 
241                                 using (StreamReader sr = new StreamReader (st, WebEncoding.FileEncoding)) {
242                                         input = sr.ReadToEnd ();
243                                 }
244                         }
245                                         
246                         if (String.IsNullOrEmpty (input))
247                                 return null;
248
249                         MatchCollection matches = AspGenerator.DirectiveRegex.Matches (input);
250                         if (matches == null || matches.Count == 0)
251                                 return null;
252                         
253                         dependencies = new SortedDictionary <string, bool> (StringComparer.InvariantCultureIgnoreCase);
254                         CaptureCollection ccNames;
255                         GroupCollection groups;
256                         string directiveName;
257                         ExtractDirectiveDependencies edd;
258                         string baseDirectory = VirtualPathUtility.GetDirectory (vpath);
259                         
260                         foreach (Match match in matches) {
261                                 groups = match.Groups;
262                                 if (groups.Count < 6)
263                                         continue;
264                                 
265                                 ccNames = groups [3].Captures;
266                                 directiveName = ccNames [0].Value;
267                                 if (!directiveAttributes.TryGetValue (directiveName, out edd))
268                                         continue;
269                                 edd (baseDirectory, ccNames, groups [5].Captures, this);
270                         }
271
272                         if (dependencies.Count == 0)
273                                 return null;
274
275                         return dependencies;
276                 }
277                 
278                 protected override string GetClassType (BaseCompiler compiler, TemplateParser parser)
279                 {
280                         if (compiler != null)
281                                 return compiler.MainClassType;
282
283                         return null;
284                 }
285                 
286                 protected override ICollection GetParserDependencies (TemplateParser parser)
287                 {
288                         if (parser != null)
289                                 return parser.Dependencies;
290                         
291                         return null;
292                 }
293                 
294                 protected override string GetParserLanguage (TemplateParser parser)
295                 {
296                         if (parser != null)
297                                 return parser.Language;
298
299                         return null;
300                 }
301                 
302                 protected override string GetCodeBehindSource (TemplateParser parser)
303                 {
304                         if (parser != null) {
305                                 string codeBehind = parser.CodeBehindSource;
306                                 if (String.IsNullOrEmpty (codeBehind))
307                                         return null;                            
308
309                                 return parser.CodeBehindSource;
310                         }
311                         
312                         return null;
313                 }
314                 
315                 protected override AspGenerator CreateAspGenerator (TemplateParser parser)
316                 {
317                         if (parser != null)
318                                 return new AspGenerator (parser);
319
320                         return null;
321                 }
322
323                 protected override List <string> GetReferencedAssemblies (TemplateParser parser)
324                 {
325                         if (parser == null)
326                                 return null;
327                         
328                         ArrayList al = parser.Assemblies;
329                         if (al == null || al.Count == 0)
330                                 return null;
331
332                         List <string> ret = new List <string> ();
333                         string loc;
334                         
335                         foreach (object o in al) {
336                                 loc = o as string;
337                                 if (loc == null)
338                                         continue;
339
340                                 if (ret.Contains (loc))
341                                         continue;
342
343                                 ret.Add (loc);
344                         }
345
346                         return ret;
347                 }
348         }
349 }
350 #endif