CodeUtils.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  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 != null)
  197. {
  198. if (par.DefaultValue.GetType().IsEnum)
  199. optionalParamString += par.DefaultValue.GetType().Name + ".";
  200. optionalParamString += par.DefaultValue.ToString();
  201. }
  202. if (TypeHasSuffix(par.ParameterType))
  203. optionalParamString += GetTypeSuffix(par.ParameterType, lang);
  204. return optionalParamString;
  205. }
  206. internal static string FixExpressionWithBrackets(string expression)
  207. {
  208. string result = expression;
  209. if (expression.StartsWith("[") && expression.EndsWith("]"))
  210. {
  211. string tempExpression = expression.Substring(1, expression.Length - 2);
  212. int firstOpen = tempExpression.IndexOf("[");
  213. int firstClose = tempExpression.IndexOf("]");
  214. int lastOpen = tempExpression.LastIndexOf("[");
  215. int lastClose = tempExpression.LastIndexOf("]");
  216. if ((firstOpen < 0 && firstClose >= 0) || (lastOpen >= 0 && lastClose < 0)
  217. || (firstOpen >= 0 && firstClose >= 0 && firstClose < firstOpen)
  218. || (lastOpen >= 0 && lastClose >= 0 && lastOpen > lastClose))
  219. {
  220. result = expression;
  221. }
  222. else
  223. {
  224. result = tempExpression;
  225. }
  226. }
  227. else
  228. {
  229. result = expression;
  230. }
  231. return result;
  232. }
  233. #endregion
  234. /// <summary>
  235. /// Returns expressions found in the text.
  236. /// </summary>
  237. /// <param name="text">Text that may contain expressions.</param>
  238. /// <param name="openBracket">The char sequence used to find the start of expression.</param>
  239. /// <param name="closeBracket">The char sequence used to find the end of expression.</param>
  240. /// <returns>Array of expressions if found; otherwise return an empty array.</returns>
  241. public static string[] GetExpressions(string text, string openBracket, string closeBracket)
  242. {
  243. List<string> expressions = new List<string>();
  244. FindTextArgs args = new FindTextArgs();
  245. args.Text = new FastString(text);
  246. args.OpenBracket = openBracket;
  247. args.CloseBracket = closeBracket;
  248. while (args.StartIndex < args.Text.Length) //text.Length
  249. {
  250. if (!FindMatchingBrackets(args, false))
  251. break;
  252. expressions.Add(args.FoundText);
  253. args.StartIndex = args.EndIndex;
  254. }
  255. return expressions.ToArray();
  256. }
  257. /// <summary>
  258. /// Gets first expression found in the text.
  259. /// </summary>
  260. /// <param name="args">Object with find arguments.</param>
  261. /// <param name="skipStrings">Indicates whether to skip strings.</param>
  262. /// <returns>The expression if found; otherwise, returns null.</returns>
  263. public static string GetExpression(FindTextArgs args, bool skipStrings)
  264. {
  265. if (args.StartIndex < args.Text.Length)
  266. {
  267. if (FindMatchingBrackets(args, skipStrings))
  268. return args.FoundText;
  269. }
  270. return null;
  271. }
  272. }
  273. }