AspGenerator.cs 52 KB

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