CoordinateParser.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Globalization;
  6. #pragma warning disable
  7. namespace Svg
  8. {
  9. internal class CoordinateParser
  10. {
  11. private enum NumState
  12. {
  13. invalid,
  14. separator,
  15. prefix,
  16. integer,
  17. decPlace,
  18. fraction,
  19. exponent,
  20. expPrefix,
  21. expValue
  22. }
  23. private string _coords;
  24. private int _pos = 0;
  25. private NumState _currState = NumState.separator;
  26. private NumState _newState = NumState.separator;
  27. private int i = 0;
  28. private bool _parseWorked = true;
  29. public int Position { get { return _pos; } }
  30. public CoordinateParser(string coords)
  31. {
  32. _coords = coords;
  33. if (string.IsNullOrEmpty(_coords)) _parseWorked = false;
  34. if (char.IsLetter(coords[0])) i++;
  35. }
  36. public bool HasMore { get { return _parseWorked; } }
  37. private bool MarkState(bool state)
  38. {
  39. _parseWorked = state;
  40. i++;
  41. return state;
  42. }
  43. public bool TryGetBool(out bool result)
  44. {
  45. while (i < _coords.Length && _parseWorked)
  46. {
  47. switch (_currState)
  48. {
  49. case NumState.separator:
  50. if (IsCoordSeparator(_coords[i]))
  51. {
  52. _newState = NumState.separator;
  53. }
  54. else if (_coords[i] == '0')
  55. {
  56. result = false;
  57. _newState = NumState.separator;
  58. _pos = i + 1;
  59. return MarkState(true);
  60. }
  61. else if (_coords[i] == '1')
  62. {
  63. result = true;
  64. _newState = NumState.separator;
  65. _pos = i + 1;
  66. return MarkState(true);
  67. }
  68. else
  69. {
  70. result = false;
  71. return MarkState(false);
  72. }
  73. break;
  74. default:
  75. result = false;
  76. return MarkState(false);
  77. }
  78. i++;
  79. }
  80. result = false;
  81. return MarkState(false);
  82. }
  83. public bool TryGetFloat(out float result)
  84. {
  85. while (i < _coords.Length && _parseWorked)
  86. {
  87. switch (_currState)
  88. {
  89. case NumState.separator:
  90. if (char.IsNumber(_coords[i]))
  91. {
  92. _newState = NumState.integer;
  93. }
  94. else if (IsCoordSeparator(_coords[i]))
  95. {
  96. _newState = NumState.separator;
  97. }
  98. else
  99. {
  100. switch (_coords[i])
  101. {
  102. case '.':
  103. _newState = NumState.decPlace;
  104. break;
  105. case '+':
  106. case '-':
  107. _newState = NumState.prefix;
  108. break;
  109. default:
  110. _newState = NumState.invalid;
  111. break;
  112. }
  113. }
  114. break;
  115. case NumState.prefix:
  116. if (char.IsNumber(_coords[i]))
  117. {
  118. _newState = NumState.integer;
  119. }
  120. else if (_coords[i] == '.')
  121. {
  122. _newState = NumState.decPlace;
  123. }
  124. else
  125. {
  126. _newState = NumState.invalid;
  127. }
  128. break;
  129. case NumState.integer:
  130. if (char.IsNumber(_coords[i]))
  131. {
  132. _newState = NumState.integer;
  133. }
  134. else if (IsCoordSeparator(_coords[i]))
  135. {
  136. _newState = NumState.separator;
  137. }
  138. else
  139. {
  140. switch (_coords[i])
  141. {
  142. case '.':
  143. _newState = NumState.decPlace;
  144. break;
  145. case 'E':
  146. case 'e':
  147. _newState = NumState.exponent;
  148. break;
  149. case '+':
  150. case '-':
  151. _newState = NumState.prefix;
  152. break;
  153. default:
  154. _newState = NumState.invalid;
  155. break;
  156. }
  157. }
  158. break;
  159. case NumState.decPlace:
  160. if (char.IsNumber(_coords[i]))
  161. {
  162. _newState = NumState.fraction;
  163. }
  164. else if (IsCoordSeparator(_coords[i]))
  165. {
  166. _newState = NumState.separator;
  167. }
  168. else
  169. {
  170. switch (_coords[i])
  171. {
  172. case 'E':
  173. case 'e':
  174. _newState = NumState.exponent;
  175. break;
  176. case '+':
  177. case '-':
  178. _newState = NumState.prefix;
  179. break;
  180. default:
  181. _newState = NumState.invalid;
  182. break;
  183. }
  184. }
  185. break;
  186. case NumState.fraction:
  187. if (char.IsNumber(_coords[i]))
  188. {
  189. _newState = NumState.fraction;
  190. }
  191. else if (IsCoordSeparator(_coords[i]))
  192. {
  193. _newState = NumState.separator;
  194. }
  195. else
  196. {
  197. switch (_coords[i])
  198. {
  199. case '.':
  200. _newState = NumState.decPlace;
  201. break;
  202. case 'E':
  203. case 'e':
  204. _newState = NumState.exponent;
  205. break;
  206. case '+':
  207. case '-':
  208. _newState = NumState.prefix;
  209. break;
  210. default:
  211. _newState = NumState.invalid;
  212. break;
  213. }
  214. }
  215. break;
  216. case NumState.exponent:
  217. if (char.IsNumber(_coords[i]))
  218. {
  219. _newState = NumState.expValue;
  220. }
  221. else if (IsCoordSeparator(_coords[i]))
  222. {
  223. _newState = NumState.invalid;
  224. }
  225. else
  226. {
  227. switch (_coords[i])
  228. {
  229. case '+':
  230. case '-':
  231. _newState = NumState.expPrefix;
  232. break;
  233. default:
  234. _newState = NumState.invalid;
  235. break;
  236. }
  237. }
  238. break;
  239. case NumState.expPrefix:
  240. if (char.IsNumber(_coords[i]))
  241. {
  242. _newState = NumState.expValue;
  243. }
  244. else
  245. {
  246. _newState = NumState.invalid;
  247. }
  248. break;
  249. case NumState.expValue:
  250. if (char.IsNumber(_coords[i]))
  251. {
  252. _newState = NumState.expValue;
  253. }
  254. else if (IsCoordSeparator(_coords[i]))
  255. {
  256. _newState = NumState.separator;
  257. }
  258. else
  259. {
  260. switch (_coords[i])
  261. {
  262. case '.':
  263. _newState = NumState.decPlace;
  264. break;
  265. case '+':
  266. case '-':
  267. _newState = NumState.prefix;
  268. break;
  269. default:
  270. _newState = NumState.invalid;
  271. break;
  272. }
  273. }
  274. break;
  275. }
  276. if (_newState < _currState)
  277. {
  278. result = float.Parse(_coords.Substring(_pos, i - _pos), NumberStyles.Float, CultureInfo.InvariantCulture);
  279. _pos = i;
  280. _currState = _newState;
  281. return MarkState(true);
  282. }
  283. else if (_newState != _currState && _currState == NumState.separator)
  284. {
  285. _pos = i;
  286. }
  287. if (_newState == NumState.invalid)
  288. {
  289. result = float.MinValue;
  290. return MarkState(false);
  291. }
  292. _currState = _newState;
  293. i++;
  294. }
  295. if (_currState == NumState.separator || !_parseWorked || _pos >= _coords.Length)
  296. {
  297. result = float.MinValue;
  298. return MarkState(false);
  299. }
  300. else
  301. {
  302. result = float.Parse(_coords.Substring(_pos, _coords.Length - _pos), NumberStyles.Float, CultureInfo.InvariantCulture);
  303. _pos = _coords.Length;
  304. return MarkState(true);
  305. }
  306. }
  307. private static bool IsCoordSeparator(char value)
  308. {
  309. switch (value)
  310. {
  311. case ' ':
  312. case '\t':
  313. case '\n':
  314. case '\r':
  315. case ',':
  316. return true;
  317. }
  318. return false;
  319. }
  320. }
  321. }
  322. #pragma warning restore