CodeUtils.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using FastReport.Data;
  5. using FastReport.Engine;
  6. using FastReport.Utils;
  7. namespace FastReport.Code
  8. {
  9. /// <summary>
  10. /// This class is used to pass find arguments to some methods of the <b>CodeUtils</b> class.
  11. /// </summary>
  12. public class FindTextArgs
  13. {
  14. private int startIndex;
  15. private int endIndex;
  16. private string openBracket;
  17. private string closeBracket;
  18. private FastString text;
  19. private string foundText;
  20. /// <summary>
  21. /// The start position of the search. After the search, this property points to
  22. /// the begin of an expression.
  23. /// </summary>
  24. public int StartIndex
  25. {
  26. get { return startIndex; }
  27. set { startIndex = value; }
  28. }
  29. /// <summary>
  30. /// After the search, this property points to the end of an expression.
  31. /// </summary>
  32. public int EndIndex
  33. {
  34. get { return endIndex; }
  35. set { endIndex = value; }
  36. }
  37. /// <summary>
  38. /// The char sequence used to find the expression's begin.
  39. /// </summary>
  40. public string OpenBracket
  41. {
  42. get { return openBracket; }
  43. set { openBracket = value; }
  44. }
  45. /// <summary>
  46. /// The char sequence used to find the expression's end.
  47. /// </summary>
  48. public string CloseBracket
  49. {
  50. get { return closeBracket; }
  51. set { closeBracket = value; }
  52. }
  53. /// <summary>
  54. /// The text with embedded expressions.
  55. /// </summary>
  56. public FastString Text
  57. {
  58. get { return text; }
  59. set { text = value; }
  60. }
  61. /// <summary>
  62. /// The last found expression.
  63. /// </summary>
  64. public string FoundText
  65. {
  66. get { return foundText; }
  67. set { foundText = value; }
  68. }
  69. }
  70. /// <summary>
  71. /// This static class contains methods that may be used to find expressions embedded
  72. /// in the object's text.
  73. /// </summary>
  74. public static class CodeUtils
  75. {
  76. internal enum Language
  77. {
  78. Cs,
  79. Vb
  80. }
  81. private static bool isTypeSuffixesInitialized = false;
  82. private static Dictionary<Type, string[]> typeSuffixes;
  83. #region Private Methods
  84. private static bool TypeHasSuffix(Type type)
  85. {
  86. return typeSuffixes.ContainsKey(type);
  87. }
  88. private static string GetTypeSuffix(Type type, Language lang)
  89. {
  90. string[] suffix;
  91. typeSuffixes.TryGetValue(type, out suffix);
  92. return suffix[(int)lang];
  93. }
  94. private static void InitializeTypeSuffixes()
  95. {
  96. typeSuffixes = new Dictionary<Type, string[]>();
  97. //c# and vb type prefixes
  98. typeSuffixes.Add(typeof(float), new string[] { "F", "F" });
  99. typeSuffixes.Add(typeof(double), new string[] { "D", "R" });
  100. typeSuffixes.Add(typeof(uint), new string[] { "U", "" });
  101. typeSuffixes.Add(typeof(long), new string[] { "L", "L" });
  102. typeSuffixes.Add(typeof(ulong), new string[] { "UL", "UL" });
  103. typeSuffixes.Add(typeof(decimal), new string[] { "M", "D" });
  104. isTypeSuffixesInitialized = true;
  105. }
  106. // adjusts StartIndex to the next char after end of string. Returns true if string is correct.
  107. private static bool SkipString(FindTextArgs args)
  108. {
  109. if (args.Text[args.StartIndex] == '"')
  110. args.StartIndex++;
  111. else
  112. return true;
  113. while (args.StartIndex < args.Text.Length)
  114. {
  115. if (args.Text[args.StartIndex] == '"')
  116. {
  117. if (args.Text[args.StartIndex - 1] != '\\')
  118. {
  119. args.StartIndex++;
  120. return true;
  121. }
  122. }
  123. args.StartIndex++;
  124. }
  125. return false;
  126. }
  127. // find matching open and close brackets starting from StartIndex. Takes strings into account.
  128. // Returns true if matching brackets found. Also returns FoundText with text inside brackets,
  129. // StartIndex pointing to the OpenBracket and EndIndex pointing to the next char after CloseBracket.
  130. private static bool FindMatchingBrackets(FindTextArgs args, bool skipLeadingStrings)
  131. {
  132. if (!skipLeadingStrings)
  133. {
  134. args.StartIndex = args.Text.IndexOf(args.OpenBracket, args.StartIndex);
  135. if (args.StartIndex == -1)
  136. return false;
  137. }
  138. int saveStartIndex = 0;
  139. int brCount = 0;
  140. while (args.StartIndex < args.Text.Length)
  141. {
  142. if (!SkipString(args))
  143. return false;
  144. if (args.StartIndex + args.OpenBracket.Length > args.Text.Length)
  145. return false;
  146. if (args.Text.SubstringCompare(args.StartIndex, args.OpenBracket))
  147. {
  148. if (brCount == 0)
  149. saveStartIndex = args.StartIndex;
  150. brCount++;
  151. }
  152. else if (args.Text.SubstringCompare(args.StartIndex, args.CloseBracket))
  153. {
  154. brCount--;
  155. if (brCount == 0)
  156. {
  157. args.EndIndex = args.StartIndex + args.CloseBracket.Length;
  158. args.StartIndex = saveStartIndex;
  159. args.FoundText = args.Text.Substring(args.StartIndex + args.OpenBracket.Length,
  160. args.EndIndex - args.StartIndex - args.OpenBracket.Length - args.CloseBracket.Length);
  161. return true;
  162. }
  163. }
  164. args.StartIndex++;
  165. }
  166. return false;
  167. }
  168. #endregion
  169. #region Internal Methods
  170. // determines whether given index is inside brackets, or is after OpenBracket
  171. internal static bool IndexInsideBrackets(FindTextArgs args)
  172. {
  173. int pos = args.StartIndex;
  174. args.StartIndex = 0;
  175. while (args.StartIndex < pos)
  176. {
  177. // find open bracket
  178. args.StartIndex = args.Text.IndexOf(args.OpenBracket, args.StartIndex);
  179. if (args.StartIndex == -1)
  180. return false;
  181. // missing close bracket
  182. if (!FindMatchingBrackets(args, false))
  183. return true;
  184. // pos is inside brackets
  185. if (args.StartIndex < pos && args.EndIndex > pos)
  186. return true;
  187. args.StartIndex = args.EndIndex;
  188. }
  189. return false;
  190. }
  191. internal static string GetOptionalParameter(System.Reflection.ParameterInfo par, Language lang)
  192. {
  193. if(!isTypeSuffixesInitialized)
  194. InitializeTypeSuffixes();
  195. string optionalParamString = " = ";
  196. if (par.DefaultValue.GetType().IsEnum)
  197. optionalParamString += par.DefaultValue.GetType().Name + ".";
  198. optionalParamString += par.DefaultValue.ToString();
  199. if (TypeHasSuffix(par.ParameterType))
  200. optionalParamString += GetTypeSuffix(par.ParameterType, lang);
  201. return optionalParamString;
  202. }
  203. internal static string FixExpressionWithBrackets(string expression)
  204. {
  205. string result = expression;
  206. if (expression.StartsWith("[") && expression.EndsWith("]"))
  207. {
  208. string tempExpression = expression.Substring(1, expression.Length - 2);
  209. int firstOpen = tempExpression.IndexOf("[");
  210. int firstClose = tempExpression.IndexOf("]");
  211. int lastOpen = tempExpression.LastIndexOf("[");
  212. int lastClose = tempExpression.LastIndexOf("]");
  213. if ((firstOpen < 0 && firstClose >= 0) || (lastOpen >= 0 && lastClose < 0)
  214. || (firstOpen >= 0 && firstClose >= 0 && firstClose < firstOpen)
  215. || (lastOpen >= 0 && lastClose >= 0 && lastOpen > lastClose))
  216. {
  217. result = expression;
  218. }
  219. else
  220. {
  221. result = tempExpression;
  222. }
  223. }
  224. else
  225. {
  226. result = expression;
  227. }
  228. return result;
  229. }
  230. #endregion
  231. /// <summary>
  232. /// Returns expressions found in the text.
  233. /// </summary>
  234. /// <param name="text">Text that may contain expressions.</param>
  235. /// <param name="openBracket">The char sequence used to find the start of expression.</param>
  236. /// <param name="closeBracket">The char sequence used to find the end of expression.</param>
  237. /// <returns>Array of expressions if found; otherwise return an empty array.</returns>
  238. public static string[] GetExpressions(string text, string openBracket, string closeBracket)
  239. {
  240. List<string> expressions = new List<string>();
  241. FindTextArgs args = new FindTextArgs();
  242. args.Text = new FastString(text);
  243. args.OpenBracket = openBracket;
  244. args.CloseBracket = closeBracket;
  245. while (args.StartIndex < args.Text.Length) //text.Length
  246. {
  247. if (!FindMatchingBrackets(args, false))
  248. break;
  249. expressions.Add(args.FoundText);
  250. args.StartIndex = args.EndIndex;
  251. }
  252. return expressions.ToArray();
  253. }
  254. /// <summary>
  255. /// Gets first expression found in the text.
  256. /// </summary>
  257. /// <param name="args">Object with find arguments.</param>
  258. /// <param name="skipStrings">Indicates whether to skip strings.</param>
  259. /// <returns>The expression if found; otherwise, returns null.</returns>
  260. public static string GetExpression(FindTextArgs args, bool skipStrings)
  261. {
  262. if (args.StartIndex < args.Text.Length)
  263. {
  264. if (FindMatchingBrackets(args, skipStrings))
  265. return args.FoundText;
  266. }
  267. return null;
  268. }
  269. }
  270. }