AspGenerator.cs 51 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715
  1. //
  2. // System.Web.Compilation.AspGenerator
  3. //
  4. // Authors:
  5. // Gonzalo Paniagua Javier ([email protected])
  6. //
  7. // (C) 2002 Ximian, Inc (http://www.ximian.com)
  8. //
  9. using System;
  10. using System.Collections;
  11. using System.ComponentModel;
  12. using System.Drawing;
  13. using System.Diagnostics;
  14. using System.IO;
  15. using System.Reflection;
  16. using System.Text;
  17. using System.Text.RegularExpressions;
  18. using System.Web.UI;
  19. using System.Web.UI.HtmlControls;
  20. using System.Web.UI.WebControls;
  21. namespace System.Web.Compilation
  22. {
  23. class ControlStack
  24. {
  25. private Stack controls;
  26. private ControlStackData top;
  27. private bool space_between_tags;
  28. private bool sbt_valid;
  29. class ControlStackData
  30. {
  31. public Type controlType;
  32. public string controlID;
  33. public string tagID;
  34. public ChildrenKind childKind;
  35. public string defaultPropertyName;
  36. public int childrenNumber;
  37. public Type container;
  38. public StringBuilder dataBindFunction;
  39. public StringBuilder codeRenderFunction;
  40. public bool useCodeRender;
  41. public ControlStackData (Type controlType,
  42. string controlID,
  43. string tagID,
  44. ChildrenKind childKind,
  45. string defaultPropertyName,
  46. Type container)
  47. {
  48. this.controlType = controlType;
  49. this.controlID = controlID;
  50. this.tagID = tagID;
  51. this.childKind = childKind;
  52. this.defaultPropertyName = defaultPropertyName;
  53. this.container = container;
  54. childrenNumber = 0;
  55. }
  56. public override string ToString ()
  57. {
  58. return controlType + " " + controlID + " " + tagID + " " + childKind + " " + childrenNumber;
  59. }
  60. }
  61. public ControlStack ()
  62. {
  63. controls = new Stack ();
  64. }
  65. private Type GetContainerType (Type type)
  66. {
  67. if (type != typeof (System.Web.UI.Control) &&
  68. !type.IsSubclassOf (typeof (System.Web.UI.Control)))
  69. return null;
  70. Type container_type;
  71. if (type == typeof (System.Web.UI.WebControls.DataList))
  72. container_type = typeof (System.Web.UI.WebControls.DataListItem);
  73. else if (type == typeof (System.Web.UI.WebControls.DataGrid))
  74. container_type = typeof (System.Web.UI.WebControls.DataGridItem);
  75. else if (type == typeof (System.Web.UI.WebControls.Repeater))
  76. container_type = typeof (System.Web.UI.WebControls.RepeaterItem);
  77. else
  78. container_type = type;
  79. return container_type;
  80. }
  81. public void Push (Type controlType,
  82. string controlID,
  83. string tagID,
  84. ChildrenKind childKind,
  85. string defaultPropertyName)
  86. {
  87. Type container_type = null;
  88. if (controlType != null){
  89. AddChild ();
  90. container_type = GetContainerType (controlType);
  91. if (container_type == null)
  92. container_type = this.Container;
  93. }
  94. top = new ControlStackData (controlType,
  95. controlID,
  96. tagID,
  97. childKind,
  98. defaultPropertyName,
  99. container_type);
  100. sbt_valid = false;
  101. controls.Push (top);
  102. }
  103. public void Pop ()
  104. {
  105. controls.Pop ();
  106. if (controls.Count != 0)
  107. top = (ControlStackData) controls.Peek ();
  108. sbt_valid = false;
  109. }
  110. public Type PeekType ()
  111. {
  112. return top.controlType;
  113. }
  114. public string PeekControlID ()
  115. {
  116. return top.controlID;
  117. }
  118. public string PeekTagID ()
  119. {
  120. return top.tagID;
  121. }
  122. public ChildrenKind PeekChildKind ()
  123. {
  124. return top.childKind;
  125. }
  126. public string PeekDefaultPropertyName ()
  127. {
  128. return top.defaultPropertyName;
  129. }
  130. public void AddChild ()
  131. {
  132. if (top != null)
  133. top.childrenNumber++;
  134. }
  135. public bool HasDataBindFunction ()
  136. {
  137. if (top.dataBindFunction == null || top.dataBindFunction.Length == 0)
  138. return false;
  139. return true;
  140. }
  141. public bool UseCodeRender
  142. {
  143. get {
  144. if (top.codeRenderFunction == null || top.codeRenderFunction.Length == 0)
  145. return false;
  146. return top.useCodeRender;
  147. }
  148. set { top.useCodeRender= value; }
  149. }
  150. public bool SpaceBetweenTags
  151. {
  152. get {
  153. if (!sbt_valid){
  154. sbt_valid = true;
  155. Type type = top.controlType;
  156. if (type.Namespace == "System.Web.UI.WebControls")
  157. space_between_tags = true;
  158. else if (type.IsSubclassOf (typeof (System.Web.UI.WebControls.WebControl)))
  159. space_between_tags = true;
  160. else if (type == typeof (System.Web.UI.HtmlControls.HtmlSelect))
  161. space_between_tags = true;
  162. else
  163. space_between_tags = false;
  164. }
  165. return space_between_tags;
  166. }
  167. }
  168. public Type Container
  169. {
  170. get { return top.container; }
  171. }
  172. public StringBuilder DataBindFunction
  173. {
  174. get {
  175. if (top.dataBindFunction == null)
  176. top.dataBindFunction = new StringBuilder ();
  177. return top.dataBindFunction;
  178. }
  179. }
  180. public StringBuilder CodeRenderFunction
  181. {
  182. get {
  183. if (top.codeRenderFunction == null)
  184. top.codeRenderFunction = new StringBuilder ();
  185. return top.codeRenderFunction;
  186. }
  187. }
  188. public int ChildIndex
  189. {
  190. get { return top.childrenNumber - 1; }
  191. }
  192. public int Count
  193. {
  194. get { return controls.Count; }
  195. }
  196. public override string ToString ()
  197. {
  198. return top.ToString () + " " + top.useCodeRender;
  199. }
  200. }
  201. class ArrayListWrapper
  202. {
  203. private ArrayList list;
  204. private int index;
  205. public ArrayListWrapper (ArrayList list)
  206. {
  207. this.list = list;
  208. index = -1;
  209. }
  210. private void CheckIndex ()
  211. {
  212. if (index == -1 || index == list.Count)
  213. throw new InvalidOperationException ();
  214. }
  215. public object Current
  216. {
  217. get {
  218. CheckIndex ();
  219. return list [index];
  220. }
  221. set {
  222. CheckIndex ();
  223. list [index] = value;
  224. }
  225. }
  226. public bool MoveNext ()
  227. {
  228. if (index < list.Count)
  229. index++;
  230. return index < list.Count;
  231. }
  232. }
  233. class AspGenerator
  234. {
  235. private object [] parts;
  236. private ArrayListWrapper elements;
  237. private StringBuilder prolog;
  238. private StringBuilder declarations;
  239. private StringBuilder script;
  240. private StringBuilder constructor;
  241. private StringBuilder init_funcs;
  242. private StringBuilder epilog;
  243. private StringBuilder current_function;
  244. private Stack functions;
  245. private ControlStack controls;
  246. private bool parse_ok;
  247. private bool has_form_tag;
  248. private AspComponentFoundry aspFoundry;
  249. private string classDecl;
  250. private string className;
  251. private string interfaces;
  252. private string parent;
  253. private string fullPath;
  254. private static string enableSessionStateLiteral = ", System.Web.SessionState.IRequiresSessionState";
  255. Hashtable options;
  256. string privateBinPath;
  257. string main_directive;
  258. static string app_file_wrong = "The content in the application file is not valid.";
  259. enum UserControlResult
  260. {
  261. OK = 0,
  262. FileNotFound = 1,
  263. CompilationFailed = 2
  264. }
  265. public AspGenerator (string pathToFile, ArrayList elements)
  266. {
  267. if (elements == null)
  268. throw new ArgumentNullException ();
  269. this.elements = new ArrayListWrapper (elements);
  270. string filename = Path.GetFileName (pathToFile);
  271. this.className = filename.Replace ('.', '_'); // Overridden by @ Page classname
  272. this.className = className.Replace ('-', '_');
  273. this.className = className.Replace (' ', '_');
  274. Options ["ClassName"] = this.className;
  275. this.fullPath = Path.GetFullPath (pathToFile);
  276. this.has_form_tag = false;
  277. AppDomainSetup setup = AppDomain.CurrentDomain.SetupInformation;
  278. privateBinPath = setup.PrivateBinPath;
  279. // This is a hack until we can run stuff in different domains
  280. if (privateBinPath == null || privateBinPath.Length == 0)
  281. privateBinPath = "bin";
  282. if (!Path.IsPathRooted (privateBinPath))
  283. privateBinPath = Path.Combine (setup.ApplicationBase, privateBinPath);
  284. Init ();
  285. }
  286. public string BaseType
  287. {
  288. get {
  289. return parent;
  290. }
  291. set {
  292. parent = value;
  293. }
  294. }
  295. public bool IsUserControl
  296. {
  297. get {
  298. return (BaseType == typeof (UserControl).ToString ());
  299. }
  300. }
  301. public bool IsPage
  302. {
  303. get {
  304. return (BaseType == typeof (Page).ToString ());
  305. }
  306. }
  307. public bool IsApplication
  308. {
  309. get {
  310. return (BaseType == typeof (HttpApplication).ToString ());
  311. }
  312. }
  313. public string Interfaces
  314. {
  315. get {
  316. return interfaces;
  317. }
  318. }
  319. public Hashtable Options {
  320. get {
  321. if (options == null)
  322. options = new Hashtable ();
  323. return options;
  324. }
  325. }
  326. public void AddInterface (string iface)
  327. {
  328. if (interfaces == "") {
  329. interfaces = iface;
  330. } else {
  331. string s = ", " + iface;
  332. if (interfaces.IndexOf (s) == -1)
  333. interfaces += s;
  334. }
  335. }
  336. private AspComponentFoundry Foundry
  337. {
  338. get {
  339. if (aspFoundry == null)
  340. aspFoundry = new AspComponentFoundry ();
  341. return aspFoundry;
  342. }
  343. }
  344. private void Init ()
  345. {
  346. controls = new ControlStack ();
  347. controls.Push (typeof (System.Web.UI.Control), "Root", null, ChildrenKind.CONTROLS, null);
  348. prolog = new StringBuilder ();
  349. declarations = new StringBuilder ();
  350. script = new StringBuilder ();
  351. constructor = new StringBuilder ();
  352. init_funcs = new StringBuilder ();
  353. epilog = new StringBuilder ();
  354. current_function = new StringBuilder ();
  355. functions = new Stack ();
  356. functions.Push (current_function);
  357. parts = new Object [6];
  358. parts [0] = prolog;
  359. parts [1] = declarations;
  360. parts [2] = script;
  361. parts [3] = constructor;
  362. parts [4] = init_funcs;
  363. parts [5] = epilog;
  364. prolog.Append ("namespace ASP {\n" +
  365. "\tusing System;\n" +
  366. "\tusing System.Collections;\n" +
  367. "\tusing System.Collections.Specialized;\n" +
  368. "\tusing System.Configuration;\n" +
  369. "\tusing System.IO;\n" +
  370. "\tusing System.Text;\n" +
  371. "\tusing System.Text.RegularExpressions;\n" +
  372. "\tusing System.Web;\n" +
  373. "\tusing System.Web.Caching;\n" +
  374. "\tusing System.Web.Security;\n" +
  375. "\tusing System.Web.SessionState;\n" +
  376. "\tusing System.Web.UI;\n" +
  377. "\tusing System.Web.UI.WebControls;\n" +
  378. "\tusing System.Web.UI.HtmlControls;\n");
  379. declarations.Append ("\t\tprivate static int __autoHandlers;\n");
  380. current_function.Append ("\t\tprivate void __BuildControlTree (System.Web.UI.Control __ctrl)\n\t\t{\n");
  381. if (!IsUserControl)
  382. current_function.Append ("\t\t\tSystem.Web.UI.IParserAccessor __parser = " +
  383. "(System.Web.UI.IParserAccessor) __ctrl;\n\n");
  384. else
  385. controls.UseCodeRender = true;
  386. }
  387. public StringReader GetCode ()
  388. {
  389. if (!parse_ok)
  390. throw new ApplicationException ("You gotta call ProcessElements () first!");
  391. StringBuilder code = new StringBuilder ();
  392. for (int i = 0; i < parts.Length; i++)
  393. code.Append ((StringBuilder) parts [i]);
  394. return new StringReader (code.ToString ());
  395. }
  396. public void Print ()
  397. {
  398. if (!parse_ok){
  399. Console.WriteLine ("//Warning!!!: Elements not correctly parsed.");
  400. }
  401. Console.Write (GetCode ().ReadToEnd ());
  402. }
  403. // Regex.Escape () make some illegal escape sequences for a C# source.
  404. private string Escape (string input)
  405. {
  406. string output = input.Replace ("\\", "\\\\");
  407. output = output.Replace ("\"", "\\\"");
  408. output = output.Replace ("\t", "\\t");
  409. output = output.Replace ("\r", "\\r");
  410. output = output.Replace ("\n", "\\n");
  411. output = output.Replace ("\n", "\\n");
  412. return output;
  413. }
  414. private void PageDirective (TagAttributes att)
  415. {
  416. if (att ["ClassName"] != null){
  417. this.className = (string) att ["ClassName"];
  418. Options ["ClassName"] = className;
  419. }
  420. if (att ["EnableSessionState"] != null){
  421. string est = (string) att ["EnableSessionState"];
  422. if (0 == String.Compare (est, "false", true))
  423. interfaces = interfaces.Replace (enableSessionStateLiteral, "");
  424. else if (0 != String.Compare (est, "true", true))
  425. throw new ApplicationException ("EnableSessionState in Page directive not set to " +
  426. "a correct value: " + est);
  427. }
  428. /*
  429. if (att ["Inherits"] != null){
  430. parent = (string) att ["Inherits"];
  431. string source_file = att ["Src"] as string;
  432. if (source_file != null)
  433. buildOptions.AppendFormat ("//<compileandreference src=\"{0}\"/>\n", source_file);
  434. else
  435. buildOptions.AppendFormat ("//<reference dll=\"{0}\"/>\n", parent);
  436. }
  437. */
  438. if (att ["CompilerOptions"] != null)
  439. Options ["CompilerOptions"] = (string) att ["CompilerOptions"];
  440. //FIXME: add support for more attributes.
  441. }
  442. void AddReference (string dll)
  443. {
  444. string references = Options ["References"] as string;
  445. if (references == null)
  446. references = dll;
  447. else
  448. references = references + " " + dll;
  449. Options ["References"] = references;
  450. }
  451. private void RegisterDirective (TagAttributes att)
  452. {
  453. string tag_prefix = (string) (att ["tagprefix"] == null ? "" : att ["tagprefix"]);
  454. string name_space = (string) (att ["namespace"] == null ? "" : att ["namespace"]);
  455. string assembly_name = (string) (att ["assembly"] == null ? "" : att ["assembly"]);
  456. string tag_name = (string) (att ["tagname"] == null ? "" : att ["tagname"]);
  457. string src = (string) (att ["src"] == null ? "" : att ["src"]);
  458. if (tag_prefix != "" && name_space != "" && assembly_name != ""){
  459. if (tag_name != "" || src != "")
  460. throw new ApplicationException ("Invalid attributes for @ Register: " +
  461. att.ToString ());
  462. prolog.AppendFormat ("\tusing {0};\n", name_space);
  463. string dll = privateBinPath + Path.DirectorySeparatorChar + assembly_name + ".dll";
  464. Foundry.RegisterFoundry (tag_prefix, dll, name_space);
  465. AddReference (dll);
  466. return;
  467. }
  468. if (tag_prefix != "" && tag_name != "" && src != ""){
  469. if (name_space != "" && assembly_name != "")
  470. throw new ApplicationException ("Invalid attributes for @ Register: " +
  471. att.ToString ());
  472. if (!src.EndsWith (".ascx"))
  473. throw new ApplicationException ("Source file extension for controls " +
  474. "must be .ascx");
  475. string pathToFile = Path.GetDirectoryName (src);
  476. if (pathToFile == "") {
  477. pathToFile = Path.GetDirectoryName (fullPath);
  478. } else if (!Path.IsPathRooted (pathToFile)) {
  479. pathToFile = Path.Combine (Path.GetDirectoryName (fullPath), pathToFile);
  480. }
  481. string srcLocation = pathToFile + Path.DirectorySeparatorChar + Path.GetFileName (src);
  482. UserControlData data = GenerateUserControl (srcLocation);
  483. switch (data.result) {
  484. case UserControlResult.OK:
  485. prolog.AppendFormat ("\tusing {0};\n", "ASP");
  486. string dll = "output" + Path.DirectorySeparatorChar + data.assemblyName + ".dll";
  487. Foundry.RegisterFoundry (tag_prefix, data.assemblyName, "ASP", data.className);
  488. AddReference (data.assemblyName);
  489. break;
  490. case UserControlResult.FileNotFound:
  491. throw new ApplicationException ("File '" + src + "' not found.");
  492. case UserControlResult.CompilationFailed:
  493. //TODO: should say where the generated .cs file is for the server to
  494. //show the source and the compiler error
  495. throw new NotImplementedException ();
  496. }
  497. return;
  498. }
  499. throw new ApplicationException ("Invalid combination of attributes in " +
  500. "@ Register: " + att.ToString ());
  501. }
  502. private void ProcessDirective ()
  503. {
  504. Directive directive = (Directive) elements.Current;
  505. TagAttributes att = directive.Attributes;
  506. if (att == null)
  507. return;
  508. string value;
  509. string id = directive.TagID.ToUpper ();
  510. switch (id){
  511. case "APPLICATION":
  512. if (main_directive != null)
  513. throw new ApplicationException (id + " not allowed after " + main_directive);
  514. if (!IsApplication)
  515. throw new ApplicationException ("@Application not allowed.");
  516. string inherits = att ["inherits"] as string;
  517. if (inherits != null)
  518. Options ["Inherits"] = inherits;
  519. main_directive = directive.TagID;
  520. break;
  521. case "PAGE":
  522. case "CONTROL":
  523. if (main_directive != null)
  524. throw new ApplicationException (id + " not allowed after " + main_directive);
  525. if (IsUserControl && id != "CONTROL")
  526. throw new ApplicationException ("@Page not allowed for user controls.");
  527. else if (IsPage && id != "PAGE")
  528. throw new ApplicationException ("@Control not allowed here. This is a page!");
  529. PageDirective (att);
  530. main_directive = directive.TagID;
  531. break;
  532. case "IMPORT":
  533. value = att ["namespace"] as string;
  534. if (value == null || att.Count > 1)
  535. throw new ApplicationException ("Wrong syntax in Import directive.");
  536. string _using = "using " + value + ";";
  537. if (prolog.ToString ().IndexOf (_using) == -1) {
  538. prolog.AppendFormat ("\t{0}\n", _using);
  539. string imports = Options ["Import"] as string;
  540. if (imports == null) {
  541. imports = value;
  542. } else {
  543. imports += "," + value;
  544. }
  545. Options ["Import"] = imports;
  546. }
  547. break;
  548. case "IMPLEMENTS":
  549. if (IsApplication)
  550. throw new ApplicationException ("@ Implements not allowed in an application file.");
  551. string iface = (string) att ["interface"];
  552. interfaces += ", " + iface;
  553. break;
  554. case "REGISTER":
  555. if (IsApplication)
  556. throw new ApplicationException ("@ Register not allowed in an application file.");
  557. RegisterDirective (att);
  558. break;
  559. case "ASSEMBLY":
  560. if (att.Count > 1)
  561. throw new ApplicationException ("Wrong syntax in Assembly directive.");
  562. string name = att ["name"] as string;
  563. string src = att ["src"] as string;
  564. if (name == null && src == null)
  565. throw new ApplicationException ("Wrong syntax in Assembly directive.");
  566. if (IsApplication && src != null)
  567. throw new ApplicationException ("'name' attribute expected.");
  568. value = (name == null) ? src : name;
  569. string assemblies = Options ["Assembly"] as string;
  570. if (assemblies == null) {
  571. assemblies = value;
  572. } else {
  573. assemblies += "," + value;
  574. }
  575. Options ["Assembly"] = assemblies;
  576. break;
  577. }
  578. }
  579. private void ProcessPlainText ()
  580. {
  581. PlainText asis = (PlainText) elements.Current;
  582. string trimmed = asis.Text.Trim ();
  583. if (trimmed == String.Empty && controls.SpaceBetweenTags == true)
  584. return;
  585. if (IsApplication) {
  586. if (trimmed != String.Empty)
  587. throw new ApplicationException (app_file_wrong);
  588. return;
  589. }
  590. if (trimmed != String.Empty && controls.PeekChildKind () != ChildrenKind.CONTROLS){
  591. string tag_id = controls.PeekTagID ();
  592. throw new ApplicationException ("Literal content not allowed for " + tag_id);
  593. }
  594. string escaped_text = Escape (asis.Text);
  595. current_function.AppendFormat ("\t\t\t__parser.AddParsedSubObject (" +
  596. "new System.Web.UI.LiteralControl (\"{0}\"));\n",
  597. escaped_text);
  598. StringBuilder codeRenderFunction = controls.CodeRenderFunction;
  599. codeRenderFunction.AppendFormat ("\t\t\t__output.Write (\"{0}\");\n", escaped_text);
  600. }
  601. private string EnumValueNameToString (Type enum_type, string value_name)
  602. {
  603. if (value_name.EndsWith ("*"))
  604. throw new ApplicationException ("Invalid property value: '" + value_name +
  605. ". It must be a valid " + enum_type.ToString () + " value.");
  606. MemberInfo [] nested_types = enum_type.FindMembers (MemberTypes.Field,
  607. BindingFlags.Public | BindingFlags.Static,
  608. Type.FilterNameIgnoreCase,
  609. value_name);
  610. if (nested_types.Length == 0)
  611. throw new ApplicationException ("Value " + value_name + " not found in enumeration " +
  612. enum_type.ToString ());
  613. if (nested_types.Length > 1)
  614. throw new ApplicationException ("Value " + value_name + " found " +
  615. nested_types.Length + " in enumeration " +
  616. enum_type.ToString ());
  617. return enum_type.ToString () + "." + nested_types [0].Name;
  618. }
  619. private void NewControlFunction (string tag_id,
  620. string control_id,
  621. Type control_type,
  622. ChildrenKind children_kind,
  623. string defaultPropertyName)
  624. {
  625. ChildrenKind prev_children_kind = controls.PeekChildKind ();
  626. if (prev_children_kind == ChildrenKind.NONE ||
  627. prev_children_kind == ChildrenKind.PROPERTIES){
  628. string prev_tag_id = controls.PeekTagID ();
  629. throw new ApplicationException ("Child controls not allowed for " + prev_tag_id);
  630. }
  631. if (prev_children_kind == ChildrenKind.DBCOLUMNS &&
  632. control_type != typeof (System.Web.UI.WebControls.DataGridColumn) &&
  633. !control_type.IsSubclassOf (typeof (System.Web.UI.WebControls.DataGridColumn)))
  634. throw new ApplicationException ("Inside " + controls.PeekTagID () + " only " +
  635. "System.Web.UI.WebControls.DataGridColum " +
  636. "objects are allowed");
  637. else if (prev_children_kind == ChildrenKind.LISTITEM &&
  638. control_type != typeof (System.Web.UI.WebControls.ListItem))
  639. throw new ApplicationException ("Inside " + controls.PeekTagID () + " only " +
  640. "System.Web.UI.WebControls.ListItem " +
  641. "objects are allowed");
  642. StringBuilder func_code = new StringBuilder ();
  643. current_function = func_code;
  644. if (0 == String.Compare (tag_id, "form", true)){
  645. if (has_form_tag)
  646. throw new ApplicationException ("Only one form server tag allowed.");
  647. has_form_tag = true;
  648. }
  649. controls.Push (control_type, control_id, tag_id, children_kind, defaultPropertyName);
  650. bool is_generic = control_type == typeof (System.Web.UI.HtmlControls.HtmlGenericControl);
  651. functions.Push (current_function);
  652. if (control_type != typeof (System.Web.UI.WebControls.ListItem))
  653. current_function.AppendFormat ("\t\tprivate System.Web.UI.Control __BuildControl_" +
  654. "{0} ()\n\t\t{{\n\t\t\t{1} __ctrl;\n\n\t\t\t__ctrl" +
  655. " = new {1} ({2});\n\t\t\tthis.{0} = __ctrl;\n",
  656. control_id, control_type,
  657. (is_generic? "\"" + tag_id + "\"" : ""));
  658. else
  659. current_function.AppendFormat ("\t\tprivate void __BuildControl_{0} ()\n\t\t{{" +
  660. "\n\t\t\t{1} __ctrl;\n\t\t\t__ctrl = new {1} ();" +
  661. "\n\t\t\tthis.{0} = __ctrl;\n",
  662. control_id, control_type);
  663. if (children_kind == ChildrenKind.CONTROLS || children_kind == ChildrenKind.OPTION)
  664. current_function.Append ("\t\t\tSystem.Web.UI.IParserAccessor __parser = " +
  665. "(System.Web.UI.IParserAccessor) __ctrl;\n");
  666. }
  667. private void DataBoundProperty (string varName, string value)
  668. {
  669. if (value == "")
  670. throw new ApplicationException ("Empty data binding tag.");
  671. string control_id = controls.PeekControlID ();
  672. string control_type_string = controls.PeekType ().ToString ();
  673. StringBuilder db_function = controls.DataBindFunction;
  674. string container = "System.Web.UI.Control";
  675. if (db_function.Length == 0)
  676. db_function.AppendFormat ("\t\tpublic void __DataBind_{0} (object sender, " +
  677. "System.EventArgs e) {{\n" +
  678. "\t\t\t{1} Container;\n" +
  679. "\t\t\t{2} target;\n" +
  680. "\t\t\ttarget = ({2}) sender;\n" +
  681. "\t\t\tContainer = ({1}) target.BindingContainer;\n",
  682. control_id, container, control_type_string);
  683. /* Removes '<%#' and '%>' */
  684. string real_value = value.Remove (0,3);
  685. real_value = real_value.Remove (real_value.Length - 2, 2);
  686. real_value = real_value.Trim ();
  687. db_function.AppendFormat ("\t\t\ttarget.{0} = System.Convert.ToString ({1});\n",
  688. varName, real_value);
  689. }
  690. /*
  691. * Returns true if it generates some code for the specified property
  692. */
  693. private void AddPropertyCode (Type prop_type, string var_name, string att, bool isDataBound)
  694. {
  695. /* FIXME: should i check for this or let the compiler fail?
  696. * if (!prop.CanWrite)
  697. * ....
  698. */
  699. if (prop_type == typeof (string)){
  700. if (att == null)
  701. throw new ApplicationException ("null value for attribute " + var_name );
  702. if (isDataBound)
  703. DataBoundProperty (var_name, att);
  704. else
  705. current_function.AppendFormat ("\t\t\t__ctrl.{0} = \"{1}\";\n", var_name,
  706. Escape (att)); // FIXME: really Escape this?
  707. }
  708. else if (prop_type.IsEnum){
  709. if (att == null)
  710. throw new ApplicationException ("null value for attribute " + var_name );
  711. string enum_value = EnumValueNameToString (prop_type, att);
  712. current_function.AppendFormat ("\t\t\t__ctrl.{0} = {1};\n", var_name, enum_value);
  713. }
  714. else if (prop_type == typeof (bool)){
  715. string value;
  716. if (att == null)
  717. value = "true"; //FIXME: is this ok for non Style properties?
  718. else if (0 == String.Compare (att, "true", true))
  719. value = "true";
  720. else if (0 == String.Compare (att, "false", true))
  721. value = "false";
  722. else
  723. throw new ApplicationException ("Value '" + att + "' is not a valid boolean.");
  724. current_function.AppendFormat ("\t\t\t__ctrl.{0} = {1};\n", var_name, value);
  725. }
  726. else if (prop_type == typeof (System.Web.UI.WebControls.Unit)){
  727. //FIXME: should use the culture specified in Page
  728. try {
  729. Unit value = Unit.Parse (att, System.Globalization.CultureInfo.InvariantCulture);
  730. } catch (Exception) {
  731. throw new ApplicationException ("'" + att + "' cannot be parsed as a unit.");
  732. }
  733. current_function.AppendFormat ("\t\t\t__ctrl.{0} = " +
  734. "System.Web.UI.WebControls.Unit.Parse (\"{1}\", " +
  735. "System.Globalization.CultureInfo.InvariantCulture);\n",
  736. var_name, att);
  737. }
  738. else if (prop_type == typeof (System.Web.UI.WebControls.FontUnit)){
  739. //FIXME: should use the culture specified in Page
  740. try {
  741. FontUnit value = FontUnit.Parse (att, System.Globalization.CultureInfo.InvariantCulture);
  742. } catch (Exception) {
  743. throw new ApplicationException ("'" + att + "' cannot be parsed as a unit.");
  744. }
  745. current_function.AppendFormat ("\t\t\t__ctrl.{0} = " +
  746. "System.Web.UI.WebControls.FontUnit.Parse (\"{1}\", " +
  747. "System.Globalization.CultureInfo.InvariantCulture);\n",
  748. var_name, att);
  749. }
  750. else if (prop_type == typeof (Int16) ||
  751. prop_type == typeof (Int32) ||
  752. prop_type == typeof (Int64)){
  753. long value;
  754. try {
  755. value = Int64.Parse (att); //FIXME: should use the culture specified in Page
  756. } catch (Exception){
  757. throw new ApplicationException (att + " is not a valid signed number " +
  758. "or is out of range.");
  759. }
  760. current_function.AppendFormat ("\t\t\t__ctrl.{0} = {1};\n", var_name, value);
  761. }
  762. else if (prop_type == typeof (UInt16) ||
  763. prop_type == typeof (UInt32) ||
  764. prop_type == typeof (UInt64)){
  765. ulong value;
  766. try {
  767. value = UInt64.Parse (att); //FIXME: should use the culture specified in Page
  768. } catch (Exception){
  769. throw new ApplicationException (att + " is not a valid unsigned number " +
  770. "or is out of range.");
  771. }
  772. current_function.AppendFormat ("\t\t\t__ctrl.{0} = {1};\n", var_name, value);
  773. }
  774. else if (prop_type == typeof (float)){
  775. float value;
  776. try {
  777. value = Single.Parse (att);
  778. } catch (Exception){
  779. throw new ApplicationException (att + " is not avalid float number or " +
  780. "is out of range.");
  781. }
  782. current_function.AppendFormat ("\t\t\t__ctrl.{0} = {1};\n", var_name, value);
  783. }
  784. else if (prop_type == typeof (double)){
  785. double value;
  786. try {
  787. value = Double.Parse (att);
  788. } catch (Exception){
  789. throw new ApplicationException (att + " is not avalid double number or " +
  790. "is out of range.");
  791. }
  792. current_function.AppendFormat ("\t\t\t__ctrl.{0} = {1};\n", var_name, value);
  793. }
  794. else if (prop_type == typeof (System.Drawing.Color)){
  795. Color c;
  796. try {
  797. c = (Color) TypeDescriptor.GetConverter (typeof (Color)).ConvertFromString (att);
  798. } catch (Exception e){
  799. throw new ApplicationException ("Color " + att + " is not a valid color.", e);
  800. }
  801. // Should i also test for IsSystemColor?
  802. // Are KnownColor members in System.Drawing.Color?
  803. if (c.IsKnownColor){
  804. current_function.AppendFormat ("\t\t\t__ctrl.{0} = System.Drawing.Color." +
  805. "{1};\n", var_name, c.Name);
  806. }
  807. else {
  808. current_function.AppendFormat ("\t\t\t__ctrl.{0} = System.Drawing.Color." +
  809. "FromArgb ({1}, {2}, {3}, {4});\n",
  810. var_name, c.A, c.R, c.G, c.B);
  811. }
  812. }
  813. else {
  814. throw new ApplicationException ("Unsupported type in property: " +
  815. prop_type.ToString ());
  816. }
  817. }
  818. private bool ProcessProperties (PropertyInfo prop, string id, TagAttributes att)
  819. {
  820. int hyphen = id.IndexOf ('-');
  821. if (hyphen == -1 && prop.CanWrite == false)
  822. return false;
  823. bool is_processed = false;
  824. bool isDataBound = att.IsDataBound ((string) att [id]);
  825. Type type = prop.PropertyType;
  826. Type style = typeof (System.Web.UI.WebControls.Style);
  827. Type fontinfo = typeof (System.Web.UI.WebControls.FontInfo);
  828. if (0 == String.Compare (prop.Name, id, true)){
  829. AddPropertyCode (type, prop.Name, (string) att [id], isDataBound);
  830. is_processed = true;
  831. } else if ((type == fontinfo || type == style || type.IsSubclassOf (style)) && hyphen != -1){
  832. string prop_field = id.Replace ("-", ".");
  833. string [] parts = prop_field.Split (new char [] {'.'});
  834. if (parts.Length != 2 || 0 != String.Compare (prop.Name, parts [0], true))
  835. return false;
  836. PropertyInfo [] subprops = type.GetProperties ();
  837. foreach (PropertyInfo subprop in subprops){
  838. if (0 != String.Compare (subprop.Name, parts [1], true))
  839. continue;
  840. if (subprop.CanWrite == false)
  841. return false;
  842. bool is_bool = subprop.PropertyType == typeof (bool);
  843. if (!is_bool && att == null){
  844. att [id] = ""; // Font-Size -> Font-Size="" as html
  845. return false;
  846. }
  847. string value;
  848. if (att == null && is_bool)
  849. value = "true"; // Font-Bold <=> Font-Bold="true"
  850. else
  851. value = (string) att [id];
  852. AddPropertyCode (subprop.PropertyType,
  853. prop.Name + "." + subprop.Name,
  854. value, isDataBound);
  855. is_processed = true;
  856. }
  857. }
  858. return is_processed;
  859. }
  860. private void AddCodeForAttributes (Type type, TagAttributes att)
  861. {
  862. EventInfo [] ev_info = type.GetEvents ();
  863. PropertyInfo [] prop_info = type.GetProperties ();
  864. bool is_processed = false;
  865. ArrayList processed = new ArrayList ();
  866. foreach (string id in att.Keys){
  867. if (0 == String.Compare (id, "runat", true) || 0 == String.Compare (id, "id", true))
  868. continue;
  869. if (id.Length > 2 && id.Substring (0, 2).ToUpper () == "ON"){
  870. string id_as_event = id.Substring (2);
  871. foreach (EventInfo ev in ev_info){
  872. if (0 == String.Compare (ev.Name, id_as_event, true)){
  873. current_function.AppendFormat (
  874. "\t\t\t__ctrl.{0} += " +
  875. "new {1} (this.{2});\n",
  876. ev.Name, ev.EventHandlerType, att [id]);
  877. is_processed = true;
  878. break;
  879. }
  880. }
  881. if (is_processed){
  882. is_processed = false;
  883. continue;
  884. }
  885. }
  886. foreach (PropertyInfo prop in prop_info){
  887. is_processed = ProcessProperties (prop, id, att);
  888. if (is_processed)
  889. break;
  890. }
  891. if (is_processed){
  892. is_processed = false;
  893. continue;
  894. }
  895. current_function.AppendFormat ("\t\t\t((System.Web.UI.IAttributeAccessor) __ctrl)." +
  896. "SetAttribute (\"{0}\", \"{1}\");\n",
  897. id, Escape ((string) att [id]));
  898. }
  899. }
  900. private void AddCodeRenderControl (StringBuilder function, int index)
  901. {
  902. function.AppendFormat ("\t\t\tparameterContainer.Controls [{0}]." +
  903. "RenderControl (__output);\n", index);
  904. }
  905. private void AddRenderMethodDelegate (StringBuilder function, string control_id)
  906. {
  907. function.AppendFormat ("\t\t\t__ctrl.SetRenderMethodDelegate (new System.Web." +
  908. "UI.RenderMethod (this.__Render_{0}));\n", control_id);
  909. }
  910. private void AddCodeRenderFunction (string codeRender, string control_id)
  911. {
  912. StringBuilder codeRenderFunction = new StringBuilder ();
  913. codeRenderFunction.AppendFormat ("\t\tprivate void __Render_{0} " +
  914. "(System.Web.UI.HtmlTextWriter __output, " +
  915. "System.Web.UI.Control parameterContainer)\n" +
  916. "\t\t{{\n", control_id);
  917. codeRenderFunction.Append (codeRender);
  918. codeRenderFunction.Append ("\t\t}\n\n");
  919. init_funcs.Append (codeRenderFunction);
  920. }
  921. private void RemoveLiterals (StringBuilder function)
  922. {
  923. string no_literals = Regex.Replace (function.ToString (),
  924. @"\t\t\t__parser.AddParsedSubObject \(" +
  925. @"new System.Web.UI.LiteralControl \(.+\);\n", "");
  926. function.Length = 0;
  927. function.Append (no_literals);
  928. }
  929. private bool FinishControlFunction (string tag_id)
  930. {
  931. if (functions.Count == 0)
  932. throw new ApplicationException ("Unbalanced open/close tags");
  933. if (controls.Count == 0)
  934. return false;
  935. string saved_id = controls.PeekTagID ();
  936. if (0 != String.Compare (saved_id, tag_id, true))
  937. return false;
  938. StringBuilder old_function = (StringBuilder) functions.Pop ();
  939. current_function = (StringBuilder) functions.Peek ();
  940. string control_id = controls.PeekControlID ();
  941. Type control_type = controls.PeekType ();
  942. bool hasDataBindFunction = controls.HasDataBindFunction ();
  943. if (hasDataBindFunction)
  944. old_function.AppendFormat ("\t\t\t__ctrl.DataBinding += new System.EventHandler " +
  945. "(this.__DataBind_{0});\n", control_id);
  946. bool useCodeRender = controls.UseCodeRender;
  947. if (useCodeRender)
  948. AddRenderMethodDelegate (old_function, control_id);
  949. if (control_type == typeof (System.Web.UI.ITemplate)){
  950. old_function.Append ("\n\t\t}\n\n");
  951. current_function.AppendFormat ("\t\t\t__ctrl.{0} = new System.Web.UI." +
  952. "CompiledTemplateBuilder (new System.Web.UI." +
  953. "BuildTemplateMethod (this.__BuildControl_{1}));\n",
  954. saved_id, control_id);
  955. }
  956. else if (control_type == typeof (System.Web.UI.WebControls.DataGridColumnCollection)){
  957. old_function.Append ("\n\t\t}\n\n");
  958. current_function.AppendFormat ("\t\t\tthis.__BuildControl_{0} (__ctrl.{1});\n",
  959. control_id, saved_id);
  960. }
  961. else if (control_type == typeof (System.Web.UI.WebControls.DataGridColumn) ||
  962. control_type.IsSubclassOf (typeof (System.Web.UI.WebControls.DataGridColumn)) ||
  963. control_type == typeof (System.Web.UI.WebControls.ListItem)){
  964. old_function.Append ("\n\t\t}\n\n");
  965. string parsed = "";
  966. string ctrl_name = "ctrl";
  967. if (controls.Container == typeof (System.Web.UI.HtmlControls.HtmlSelect)){
  968. parsed = "ParsedSubObject";
  969. ctrl_name = "parser";
  970. }
  971. current_function.AppendFormat ("\t\t\tthis.__BuildControl_{0} ();\n" +
  972. "\t\t\t__{1}.Add{2} (this.{0});\n\n",
  973. control_id, ctrl_name, parsed);
  974. }
  975. else if (controls.PeekChildKind () == ChildrenKind.LISTITEM){
  976. old_function.Append ("\n\t\t}\n\n");
  977. init_funcs.Append (old_function); // Closes the BuildList function
  978. old_function = (StringBuilder) functions.Pop ();
  979. current_function = (StringBuilder) functions.Peek ();
  980. old_function.AppendFormat ("\n\t\t\tthis.__BuildControl_{0} (__ctrl.{1});\n\t\t\t" +
  981. "return __ctrl;\n\t\t}}\n\n",
  982. control_id, controls.PeekDefaultPropertyName ());
  983. controls.Pop ();
  984. control_id = controls.PeekControlID ();
  985. current_function.AppendFormat ("\t\t\tthis.__BuildControl_{0} ();\n\t\t\t__parser." +
  986. "AddParsedSubObject (this.{0});\n\n", control_id);
  987. }
  988. else {
  989. old_function.Append ("\n\t\t\treturn __ctrl;\n\t\t}\n\n");
  990. current_function.AppendFormat ("\t\t\tthis.__BuildControl_{0} ();\n\t\t\t__parser." +
  991. "AddParsedSubObject (this.{0});\n\n", control_id);
  992. }
  993. if (useCodeRender)
  994. RemoveLiterals (old_function);
  995. init_funcs.Append (old_function);
  996. if (useCodeRender)
  997. AddCodeRenderFunction (controls.CodeRenderFunction.ToString (), control_id);
  998. if (hasDataBindFunction){
  999. StringBuilder db_function = controls.DataBindFunction;
  1000. db_function.Append ("\t\t}\n\n");
  1001. init_funcs.Append (db_function);
  1002. }
  1003. // Avoid getting empty stacks for unbalanced open/close tags
  1004. if (controls.Count > 1){
  1005. controls.Pop ();
  1006. AddCodeRenderControl (controls.CodeRenderFunction, controls.ChildIndex);
  1007. }
  1008. return true;
  1009. }
  1010. private void ProcessHtmlControlTag ()
  1011. {
  1012. HtmlControlTag html_ctrl = (HtmlControlTag) elements.Current;
  1013. if (html_ctrl.TagID.ToUpper () == "SCRIPT"){
  1014. //FIXME: if the is script is to be read from disk, do it!
  1015. if (html_ctrl.SelfClosing)
  1016. throw new ApplicationException ("Read script from file not supported yet.");
  1017. if (elements.MoveNext () == false)
  1018. throw new ApplicationException ("Error after " + html_ctrl.ToString ());
  1019. if (elements.Current is PlainText){
  1020. script.Append (((PlainText) elements.Current).Text);
  1021. if (!elements.MoveNext ())
  1022. throw new ApplicationException ("Error after " +
  1023. elements.Current.ToString ());
  1024. }
  1025. if (elements.Current is CloseTag)
  1026. elements.MoveNext ();
  1027. return;
  1028. } else if (IsApplication) {
  1029. throw new ApplicationException (app_file_wrong);
  1030. }
  1031. Type controlType = html_ctrl.ControlType;
  1032. declarations.AppendFormat ("\t\tprotected {0} {1};\n", controlType, html_ctrl.ControlID);
  1033. ChildrenKind children_kind;
  1034. if (0 != String.Compare (html_ctrl.TagID, "select", true))
  1035. children_kind = html_ctrl.IsContainer ? ChildrenKind.CONTROLS :
  1036. ChildrenKind.NONE;
  1037. else
  1038. children_kind = ChildrenKind.OPTION;
  1039. NewControlFunction (html_ctrl.TagID, html_ctrl.ControlID, controlType, children_kind, null);
  1040. current_function.AppendFormat ("\t\t\t__ctrl.ID = \"{0}\";\n", html_ctrl.ControlID);
  1041. AddCodeForAttributes (html_ctrl.ControlType, html_ctrl.Attributes);
  1042. if (!html_ctrl.SelfClosing)
  1043. JustDoIt ();
  1044. else
  1045. FinishControlFunction (html_ctrl.TagID);
  1046. }
  1047. // Closing is performed in FinishControlFunction ()
  1048. private void NewBuildListFunction (AspComponent component)
  1049. {
  1050. string control_id = Tag.GetDefaultID ();
  1051. controls.Push (component.ComponentType,
  1052. control_id,
  1053. component.TagID,
  1054. ChildrenKind.LISTITEM,
  1055. component.DefaultPropertyName);
  1056. current_function = new StringBuilder ();
  1057. functions.Push (current_function);
  1058. current_function.AppendFormat ("\t\tprivate void __BuildControl_{0} " +
  1059. "(System.Web.UI.WebControls.ListItemCollection __ctrl)\n" +
  1060. "\t\t{{\n", control_id);
  1061. }
  1062. private void ProcessComponent ()
  1063. {
  1064. AspComponent component = (AspComponent) elements.Current;
  1065. Type component_type = component.ComponentType;
  1066. declarations.AppendFormat ("\t\tprotected {0} {1};\n", component_type, component.ControlID);
  1067. NewControlFunction (component.TagID, component.ControlID, component_type,
  1068. component.ChildrenKind, component.DefaultPropertyName);
  1069. if (component_type.IsSubclassOf (typeof (System.Web.UI.UserControl)))
  1070. current_function.Append ("\t\t\t__ctrl.InitializeAsUserControl (Page);\n");
  1071. if (component_type.IsSubclassOf (typeof (System.Web.UI.Control)))
  1072. current_function.AppendFormat ("\t\t\t__ctrl.ID = \"{0}\";\n", component.ControlID);
  1073. AddCodeForAttributes (component.ComponentType, component.Attributes);
  1074. if (component.ChildrenKind == ChildrenKind.LISTITEM)
  1075. NewBuildListFunction (component);
  1076. if (!component.SelfClosing)
  1077. JustDoIt ();
  1078. else
  1079. FinishControlFunction (component.TagID);
  1080. }
  1081. private void ProcessServerObjectTag ()
  1082. {
  1083. ServerObjectTag obj = (ServerObjectTag) elements.Current;
  1084. declarations.AppendFormat ("\t\tprivate {0} cached{1};\n", obj.ObjectClass, obj.ObjectID);
  1085. constructor.AppendFormat ("\n\t\tprivate {0} {1}\n\t\t{{\n\t\t\tget {{\n\t\t\t\t" +
  1086. "if (this.cached{1} == null)\n\t\t\t\t\tthis.cached{1} = " +
  1087. "new {0} ();\n\t\t\t\treturn cached{1};\n\t\t\t}}\n\t\t}}\n\n",
  1088. obj.ObjectClass, obj.ObjectID);
  1089. }
  1090. // Creates a new function that sets the values of subproperties.
  1091. private void NewStyleFunction (PropertyTag tag)
  1092. {
  1093. current_function = new StringBuilder ();
  1094. string prop_id = tag.PropertyID;
  1095. Type prop_type = tag.PropertyType;
  1096. // begin function
  1097. current_function.AppendFormat ("\t\tprivate void __BuildControl_{0} ({1} __ctrl)\n" +
  1098. "\t\t{{\n", prop_id, prop_type);
  1099. // Add property initialization code
  1100. PropertyInfo [] subprop_info = prop_type.GetProperties ();
  1101. TagAttributes att = tag.Attributes;
  1102. string subprop_name = null;
  1103. foreach (string id in att.Keys){
  1104. if (0 == String.Compare (id, "runat", true) || 0 == String.Compare (id, "id", true))
  1105. continue;
  1106. bool is_processed = false;
  1107. foreach (PropertyInfo subprop in subprop_info){
  1108. is_processed = ProcessProperties (subprop, id, att);
  1109. if (is_processed){
  1110. subprop_name = subprop.Name;
  1111. break;
  1112. }
  1113. }
  1114. if (subprop_name == null)
  1115. throw new ApplicationException ("Property " + tag.TagID + " does not have " +
  1116. "a " + id + " subproperty.");
  1117. }
  1118. // Finish function
  1119. current_function.Append ("\n\t\t}\n\n");
  1120. init_funcs.Append (current_function);
  1121. current_function = (StringBuilder) functions.Peek ();
  1122. current_function.AppendFormat ("\t\t\tthis.__BuildControl_{0} (__ctrl.{1});\n",
  1123. prop_id, tag.PropertyName);
  1124. if (!tag.SelfClosing){
  1125. // Next tag should be the closing tag
  1126. controls.Push (null, null, null, ChildrenKind.NONE, null);
  1127. bool closing_tag_found = false;
  1128. Element elem;
  1129. while (!closing_tag_found && elements.MoveNext ()){
  1130. elem = (Element) elements.Current;
  1131. if (elem is PlainText)
  1132. ProcessPlainText ();
  1133. else if (!(elem is CloseTag))
  1134. throw new ApplicationException ("Tag " + tag.TagID +
  1135. " not properly closed.");
  1136. else
  1137. closing_tag_found = true;
  1138. }
  1139. if (!closing_tag_found)
  1140. throw new ApplicationException ("Tag " + tag.TagID + " not properly closed.");
  1141. controls.Pop ();
  1142. }
  1143. }
  1144. // This one just opens the function. Closing is performed in FinishControlFunction ()
  1145. private void NewTemplateFunction (PropertyTag tag)
  1146. {
  1147. /*
  1148. * FIXME
  1149. * This function does almost the same as NewControlFunction.
  1150. * Consider merging.
  1151. */
  1152. string prop_id = tag.PropertyID;
  1153. Type prop_type = tag.PropertyType;
  1154. string tag_id = tag.PropertyName; // Real property name used in FinishControlFunction
  1155. controls.Push (prop_type, prop_id, tag_id, ChildrenKind.CONTROLS, null);
  1156. current_function = new StringBuilder ();
  1157. functions.Push (current_function);
  1158. current_function.AppendFormat ("\t\tprivate void __BuildControl_{0} " +
  1159. "(System.Web.UI.Control __ctrl)\n" +
  1160. "\t\t{{\n" +
  1161. "\t\t\tSystem.Web.UI.IParserAccessor __parser " +
  1162. "= (System.Web.UI.IParserAccessor) __ctrl;\n" , prop_id);
  1163. }
  1164. // Closing is performed in FinishControlFunction ()
  1165. private void NewDBColumnFunction (PropertyTag tag)
  1166. {
  1167. /*
  1168. * FIXME
  1169. * This function also does almost the same as NewControlFunction.
  1170. * Consider merging.
  1171. */
  1172. string prop_id = tag.PropertyID;
  1173. Type prop_type = tag.PropertyType;
  1174. string tag_id = tag.PropertyName; // Real property name used in FinishControlFunction
  1175. controls.Push (prop_type, prop_id, tag_id, ChildrenKind.DBCOLUMNS, null);
  1176. current_function = new StringBuilder ();
  1177. functions.Push (current_function);
  1178. current_function.AppendFormat ("\t\tprivate void __BuildControl_{0} " +
  1179. "(System.Web.UI.WebControl.DataGridColumnCollection __ctrl)\n" +
  1180. "\t\t{{\n", prop_id);
  1181. }
  1182. private void NewPropertyFunction (PropertyTag tag)
  1183. {
  1184. if (tag.PropertyType == typeof (System.Web.UI.WebControls.Style) ||
  1185. tag.PropertyType.IsSubclassOf (typeof (System.Web.UI.WebControls.Style)))
  1186. NewStyleFunction (tag);
  1187. else if (tag.PropertyType == typeof (System.Web.UI.ITemplate))
  1188. NewTemplateFunction (tag);
  1189. else if (tag.PropertyType == typeof (System.Web.UI.WebControls.DataGridColumnCollection))
  1190. NewDBColumnFunction (tag);
  1191. else
  1192. throw new ApplicationException ("Other than Style and ITemplate not supported yet. " +
  1193. tag.PropertyType);
  1194. }
  1195. private void ProcessHtmlTag ()
  1196. {
  1197. Tag tag = (Tag) elements.Current;
  1198. ChildrenKind child_kind = controls.PeekChildKind ();
  1199. if (child_kind == ChildrenKind.NONE){
  1200. string tag_id = controls.PeekTagID ();
  1201. throw new ApplicationException (tag + " not allowed inside " + tag_id);
  1202. }
  1203. if (child_kind == ChildrenKind.OPTION){
  1204. if (0 != String.Compare (tag.TagID, "option", true))
  1205. throw new ApplicationException ("Only <option> tags allowed inside <select>.");
  1206. string default_id = Tag.GetDefaultID ();
  1207. Type type = typeof (System.Web.UI.WebControls.ListItem);
  1208. declarations.AppendFormat ("\t\tprotected {0} {1};\n", type, default_id);
  1209. NewControlFunction (tag.TagID, default_id, type, ChildrenKind.CONTROLS, null);
  1210. return;
  1211. }
  1212. if (child_kind == ChildrenKind.CONTROLS){
  1213. elements.Current = new PlainText (((Tag) elements.Current).PlainHtml);
  1214. ProcessPlainText ();
  1215. return;
  1216. }
  1217. // Now child_kind should be PROPERTIES, so only allow tag_id == property
  1218. Type control_type = controls.PeekType ();
  1219. PropertyInfo [] prop_info = control_type.GetProperties ();
  1220. bool is_processed = false;
  1221. foreach (PropertyInfo prop in prop_info){
  1222. if (0 == String.Compare (prop.Name, tag.TagID, true)){
  1223. PropertyTag prop_tag = new PropertyTag (tag, prop.PropertyType, prop.Name);
  1224. NewPropertyFunction (prop_tag);
  1225. is_processed = true;
  1226. break;
  1227. }
  1228. }
  1229. if (!is_processed){
  1230. string tag_id = controls.PeekTagID ();
  1231. throw new ApplicationException (tag.TagID + " is not a property of " + control_type);
  1232. }
  1233. }
  1234. private Tag Map (Tag tag)
  1235. {
  1236. int pos = tag.TagID.IndexOf (":");
  1237. if (tag is CloseTag ||
  1238. ((tag.Attributes == null ||
  1239. !tag.Attributes.IsRunAtServer ()) && pos == -1))
  1240. return tag;
  1241. if (pos == -1){
  1242. if (0 == String.Compare (tag.TagID, "object", true))
  1243. return new ServerObjectTag (tag);
  1244. return new HtmlControlTag (tag);
  1245. }
  1246. string foundry_name = tag.TagID.Substring (0, pos);
  1247. string component_name = tag.TagID.Substring (pos + 1);
  1248. if (Foundry.LookupFoundry (foundry_name) == false)
  1249. throw new ApplicationException ("Cannot find foundry for alias'" + foundry_name + "'");
  1250. AspComponent component = Foundry.MakeAspComponent (foundry_name, component_name, tag);
  1251. if (component == null)
  1252. throw new ApplicationException ("Cannot find component '" + component_name +
  1253. "' for alias '" + foundry_name + "'");
  1254. return component;
  1255. }
  1256. private void ProcessCloseTag ()
  1257. {
  1258. CloseTag close_tag = (CloseTag) elements.Current;
  1259. if (FinishControlFunction (close_tag.TagID))
  1260. return;
  1261. elements.Current = new PlainText (close_tag.PlainHtml);
  1262. ProcessPlainText ();
  1263. }
  1264. private void ProcessDataBindingLiteral ()
  1265. {
  1266. DataBindingTag dataBinding = (DataBindingTag) elements.Current;
  1267. string actual_value = dataBinding.Data;
  1268. if (actual_value == "")
  1269. throw new ApplicationException ("Empty data binding tag.");
  1270. if (controls.PeekChildKind () != ChildrenKind.CONTROLS)
  1271. throw new ApplicationException ("Data bound content not allowed for " +
  1272. controls.PeekTagID ());
  1273. StringBuilder db_function = new StringBuilder ();
  1274. string control_id = Tag.GetDefaultID ();
  1275. string control_type_string = "System.Web.UI.DataBoundLiteralControl";
  1276. declarations.AppendFormat ("\t\tprotected {0} {1};\n", control_type_string, control_id);
  1277. // Build the control
  1278. db_function.AppendFormat ("\t\tprivate System.Web.UI.Control __BuildControl_{0} ()\n" +
  1279. "\t\t{{\n\t\t\t{1} __ctrl;\n\n" +
  1280. "\t\t\t__ctrl = new {1} (0, 1);\n" +
  1281. "\t\t\tthis.{0} = __ctrl;\n" +
  1282. "\t\t\t__ctrl.DataBinding += new System.EventHandler " +
  1283. "(this.__DataBind_{0});\n" +
  1284. "\t\t\treturn __ctrl;\n"+
  1285. "\t\t}}\n\n",
  1286. control_id, control_type_string);
  1287. // DataBinding handler
  1288. db_function.AppendFormat ("\t\tpublic void __DataBind_{0} (object sender, " +
  1289. "System.EventArgs e) {{\n" +
  1290. "\t\t\t{1} Container;\n" +
  1291. "\t\t\t{2} target;\n" +
  1292. "\t\t\ttarget = ({2}) sender;\n" +
  1293. "\t\t\tContainer = ({1}) target.BindingContainer;\n" +
  1294. "\t\t\ttarget.SetDataBoundString (0, System.Convert." +
  1295. "ToString ({3}));\n" +
  1296. "\t\t}}\n\n",
  1297. control_id, controls.Container, control_type_string,
  1298. actual_value);
  1299. init_funcs.Append (db_function);
  1300. current_function.AppendFormat ("\t\t\tthis.__BuildControl_{0} ();\n\t\t\t__parser." +
  1301. "AddParsedSubObject (this.{0});\n\n", control_id);
  1302. }
  1303. private void ProcessCodeRenderTag ()
  1304. {
  1305. CodeRenderTag code_tag = (CodeRenderTag) elements.Current;
  1306. controls.UseCodeRender = true;
  1307. if (code_tag.IsVarName)
  1308. controls.CodeRenderFunction.AppendFormat ("\t\t\t__output.Write ({0});\n",
  1309. code_tag.Code);
  1310. else
  1311. controls.CodeRenderFunction.AppendFormat ("\t\t\t{0}\n", code_tag.Code);
  1312. }
  1313. public void ProcessElements ()
  1314. {
  1315. JustDoIt ();
  1316. End ();
  1317. parse_ok = true;
  1318. }
  1319. private void JustDoIt ()
  1320. {
  1321. Element element;
  1322. while (elements.MoveNext ()){
  1323. element = (Element) elements.Current;
  1324. if (element is Directive){
  1325. ProcessDirective ();
  1326. } else if (element is PlainText){
  1327. ProcessPlainText ();
  1328. } else if (element is DataBindingTag){
  1329. if (IsApplication)
  1330. throw new ApplicationException (app_file_wrong);
  1331. ProcessDataBindingLiteral ();
  1332. } else if (element is CodeRenderTag){
  1333. if (IsApplication)
  1334. throw new ApplicationException (app_file_wrong);
  1335. ProcessCodeRenderTag ();
  1336. } else {
  1337. elements.Current = Map ((Tag) element);
  1338. if (elements.Current is ServerObjectTag) {
  1339. ProcessServerObjectTag ();
  1340. continue;
  1341. }
  1342. if (elements.Current is HtmlControlTag) {
  1343. ProcessHtmlControlTag ();
  1344. continue;
  1345. }
  1346. if (IsApplication)
  1347. throw new ApplicationException (app_file_wrong);
  1348. else if (elements.Current is AspComponent)
  1349. ProcessComponent ();
  1350. else if (elements.Current is CloseTag)
  1351. ProcessCloseTag ();
  1352. else if (elements.Current is Tag)
  1353. ProcessHtmlTag ();
  1354. else
  1355. throw new ApplicationException ("This place should not be reached.");
  1356. }
  1357. }
  1358. }
  1359. private void End ()
  1360. {
  1361. classDecl = "\tpublic class " + className + " : " + parent + interfaces + " {\n";
  1362. prolog.Append ("\n" + classDecl);
  1363. declarations.Append ("\t\tprivate static bool __intialized = false;\n\n");
  1364. if (IsPage)
  1365. declarations.Append ("\t\tprivate static ArrayList __fileDependencies;\n\n");
  1366. // adds the constructor
  1367. constructor.AppendFormat ("\t\tpublic {0} ()\n\t\t{{\n", className);
  1368. if (!IsApplication)
  1369. constructor.Append ("\t\t\tSystem.Collections.ArrayList dependencies;\n\n");
  1370. constructor.AppendFormat ("\t\t\tif (ASP.{0}.__intialized == false){{\n", className);
  1371. if (IsPage) {
  1372. constructor.AppendFormat ("\t\t\t\tdependencies = new System.Collections.ArrayList ();\n" +
  1373. "\t\t\t\tdependencies.Add (@\"{1}\");\n" +
  1374. "\t\t\t\tASP.{0}.__fileDependencies = dependencies;\n",
  1375. className, fullPath);
  1376. }
  1377. constructor.AppendFormat ("\t\t\t\tASP.{0}.__intialized = true;\n\t\t\t}}\n\t\t}}\n\n",
  1378. className);
  1379. if (!IsApplication) {
  1380. //FIXME: add AutoHandlers: don't know what for...yet!
  1381. constructor.AppendFormat (
  1382. "\t\tprotected override int AutoHandlers\n\t\t{{\n" +
  1383. "\t\t\tget {{ return ASP.{0}.__autoHandlers; }}\n" +
  1384. "\t\t\tset {{ ASP.{0}.__autoHandlers = value; }}\n" +
  1385. "\t\t}}\n\n", className);
  1386. constructor.Append (
  1387. "\t\tprotected System.Web.HttpApplication ApplicationInstance\n\t\t{\n" +
  1388. "\t\t\tget { return (System.Web.HttpApplication) this.Context.ApplicationInstance; }\n" +
  1389. "\t\t}\n\n");
  1390. //FIXME: add TemplateSourceDirectory: don't know what for...yet!
  1391. //FIXME: it should be the path from the root where the file resides
  1392. constructor.Append (
  1393. "\t\tpublic override string TemplateSourceDirectory\n\t\t{\n" +
  1394. "\t\t\tget { return \"/dummypath\"; }\n" +
  1395. "\t\t}\n\n");
  1396. epilog.Append ("\n\t\tprotected override void FrameworkInitialize ()\n\t\t{\n" +
  1397. "\t\t\tthis.__BuildControlTree (this);\n");
  1398. if (IsPage) {
  1399. epilog.AppendFormat ("\t\t\tthis.FileDependencies = ASP.{0}.__fileDependencies;\n" +
  1400. "\t\t\tthis.EnableViewStateMac = true;\n", className);
  1401. }
  1402. epilog.Append ("\t\t}\n\n");
  1403. }
  1404. if (IsPage) {
  1405. Random rnd = new Random ();
  1406. epilog.AppendFormat ("\t\tpublic override int GetTypeHashCode ()\n\t\t{{\n" +
  1407. "\t\t\treturn {0};\n" +
  1408. "\t\t}}\n", rnd.Next ());
  1409. }
  1410. epilog.Append ("\t}\n}\n");
  1411. // Closes the currently opened tags
  1412. StringBuilder old_function = current_function;
  1413. string control_id;
  1414. while (functions.Count > 1){
  1415. old_function.Append ("\n\t\t\treturn __ctrl;\n\t\t}\n\n");
  1416. init_funcs.Append (old_function);
  1417. control_id = controls.PeekControlID ();
  1418. FinishControlFunction (control_id);
  1419. controls.AddChild ();
  1420. old_function = (StringBuilder) functions.Pop ();
  1421. current_function = (StringBuilder) functions.Peek ();
  1422. controls.Pop ();
  1423. }
  1424. bool useCodeRender = controls.UseCodeRender;
  1425. if (useCodeRender){
  1426. RemoveLiterals (current_function);
  1427. AddRenderMethodDelegate (current_function, controls.PeekControlID ());
  1428. }
  1429. current_function.Append ("\t\t}\n\n");
  1430. init_funcs.Append (current_function);
  1431. if (useCodeRender)
  1432. AddCodeRenderFunction (controls.CodeRenderFunction.ToString (), controls.PeekControlID ());
  1433. functions.Pop ();
  1434. }
  1435. //
  1436. // Functions related to compilation of user controls
  1437. //
  1438. private static char dirSeparator = Path.DirectorySeparatorChar;
  1439. struct UserControlData
  1440. {
  1441. public UserControlResult result;
  1442. public string className;
  1443. public string assemblyName;
  1444. }
  1445. private static UserControlData GenerateUserControl (string src)
  1446. {
  1447. UserControlData data = new UserControlData ();
  1448. data.result = UserControlResult.OK;
  1449. if (!File.Exists (src)) {
  1450. data.result = UserControlResult.FileNotFound;
  1451. return data;
  1452. }
  1453. string dll = Path.GetTempFileName () + ".dll";
  1454. UserControlCompiler compiler = new UserControlCompiler (new UserControlParser (src), dll);
  1455. Type t = compiler.GetCompiledType ();
  1456. if (t == null) {
  1457. data.result = UserControlResult.CompilationFailed;
  1458. return data;
  1459. }
  1460. data.className = t.Name;
  1461. data.assemblyName = dll;
  1462. return data;
  1463. }
  1464. }
  1465. }