XmlConverter.cs 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180
  1. //------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //------------------------------------------------------------
  4. // PERF, [....], [....]: Make LookupNamespace do something smarter when lots of names
  5. // PERF, [....], [....]: Make Attribute lookup smarter when lots of attributes
  6. // PERF: [....], [....]: Compare safe/unsafe versions
  7. namespace System.Xml
  8. {
  9. using System;
  10. using System.Diagnostics.CodeAnalysis;
  11. using System.Globalization;
  12. using System.Runtime;
  13. using System.Runtime.Serialization;
  14. using System.Security;
  15. using System.Text;
  16. static class XmlConverter
  17. {
  18. public const int MaxDateTimeChars = 64;
  19. public const int MaxInt32Chars = 16;
  20. public const int MaxInt64Chars = 32;
  21. public const int MaxBoolChars = 5;
  22. public const int MaxFloatChars = 16;
  23. public const int MaxDoubleChars = 32;
  24. public const int MaxDecimalChars = 40;
  25. public const int MaxUInt64Chars = 32;
  26. public const int MaxPrimitiveChars = MaxDateTimeChars;
  27. static char[] whiteSpaceChars = new char[] { ' ', '\t', '\n', '\r' };
  28. static UTF8Encoding utf8Encoding;
  29. static UnicodeEncoding unicodeEncoding;
  30. static Base64Encoding base64Encoding;
  31. static public Base64Encoding Base64Encoding
  32. {
  33. get
  34. {
  35. if (base64Encoding == null)
  36. base64Encoding = new Base64Encoding();
  37. return base64Encoding;
  38. }
  39. }
  40. static UTF8Encoding UTF8Encoding
  41. {
  42. get
  43. {
  44. if (utf8Encoding == null)
  45. utf8Encoding = new UTF8Encoding(false, true);
  46. return utf8Encoding;
  47. }
  48. }
  49. static UnicodeEncoding UnicodeEncoding
  50. {
  51. get
  52. {
  53. if (unicodeEncoding == null)
  54. unicodeEncoding = new UnicodeEncoding(false, false, true);
  55. return unicodeEncoding;
  56. }
  57. }
  58. static public bool ToBoolean(string value)
  59. {
  60. try
  61. {
  62. return XmlConvert.ToBoolean(value);
  63. }
  64. catch (ArgumentException exception)
  65. {
  66. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "Boolean", exception));
  67. }
  68. catch (FormatException exception)
  69. {
  70. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "Boolean", exception));
  71. }
  72. }
  73. static public bool ToBoolean(byte[] buffer, int offset, int count)
  74. {
  75. if (count == 1)
  76. {
  77. byte ch = buffer[offset];
  78. if (ch == (byte)'1')
  79. return true;
  80. else if (ch == (byte)'0')
  81. return false;
  82. }
  83. return ToBoolean(ToString(buffer, offset, count));
  84. }
  85. static public int ToInt32(string value)
  86. {
  87. try
  88. {
  89. return XmlConvert.ToInt32(value);
  90. }
  91. catch (ArgumentException exception)
  92. {
  93. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "Int32", exception));
  94. }
  95. catch (FormatException exception)
  96. {
  97. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "Int32", exception));
  98. }
  99. catch (OverflowException exception)
  100. {
  101. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "Int32", exception));
  102. }
  103. }
  104. static public int ToInt32(byte[] buffer, int offset, int count)
  105. {
  106. int value;
  107. if (TryParseInt32(buffer, offset, count, out value))
  108. return value;
  109. return ToInt32(ToString(buffer, offset, count));
  110. }
  111. static public Int64 ToInt64(string value)
  112. {
  113. try
  114. {
  115. return XmlConvert.ToInt64(value);
  116. }
  117. catch (ArgumentException exception)
  118. {
  119. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "Int64", exception));
  120. }
  121. catch (FormatException exception)
  122. {
  123. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "Int64", exception));
  124. }
  125. catch (OverflowException exception)
  126. {
  127. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "Int64", exception));
  128. }
  129. }
  130. static public Int64 ToInt64(byte[] buffer, int offset, int count)
  131. {
  132. long value;
  133. if (TryParseInt64(buffer, offset, count, out value))
  134. return value;
  135. return ToInt64(ToString(buffer, offset, count));
  136. }
  137. static public float ToSingle(string value)
  138. {
  139. try
  140. {
  141. return XmlConvert.ToSingle(value);
  142. }
  143. catch (ArgumentException exception)
  144. {
  145. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "float", exception));
  146. }
  147. catch (FormatException exception)
  148. {
  149. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "float", exception));
  150. }
  151. catch (OverflowException exception)
  152. {
  153. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "float", exception));
  154. }
  155. }
  156. static public float ToSingle(byte[] buffer, int offset, int count)
  157. {
  158. float value;
  159. if (TryParseSingle(buffer, offset, count, out value))
  160. return value;
  161. return ToSingle(ToString(buffer, offset, count));
  162. }
  163. static public double ToDouble(string value)
  164. {
  165. try
  166. {
  167. return XmlConvert.ToDouble(value);
  168. }
  169. catch (ArgumentException exception)
  170. {
  171. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "double", exception));
  172. }
  173. catch (FormatException exception)
  174. {
  175. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "double", exception));
  176. }
  177. catch (OverflowException exception)
  178. {
  179. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "double", exception));
  180. }
  181. }
  182. static public double ToDouble(byte[] buffer, int offset, int count)
  183. {
  184. double value;
  185. if (TryParseDouble(buffer, offset, count, out value))
  186. return value;
  187. return ToDouble(ToString(buffer, offset, count));
  188. }
  189. static public decimal ToDecimal(string value)
  190. {
  191. try
  192. {
  193. return XmlConvert.ToDecimal(value);
  194. }
  195. catch (ArgumentException exception)
  196. {
  197. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "decimal", exception));
  198. }
  199. catch (FormatException exception)
  200. {
  201. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "decimal", exception));
  202. }
  203. catch (OverflowException exception)
  204. {
  205. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "decimal", exception));
  206. }
  207. }
  208. static public decimal ToDecimal(byte[] buffer, int offset, int count)
  209. {
  210. return ToDecimal(ToString(buffer, offset, count));
  211. }
  212. static public DateTime ToDateTime(Int64 value)
  213. {
  214. try
  215. {
  216. return DateTime.FromBinary(value);
  217. }
  218. catch (ArgumentException exception)
  219. {
  220. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(ToString(value), "DateTime", exception));
  221. }
  222. }
  223. static public DateTime ToDateTime(string value)
  224. {
  225. try
  226. {
  227. return XmlConvert.ToDateTime(value, XmlDateTimeSerializationMode.RoundtripKind);
  228. }
  229. catch (ArgumentException exception)
  230. {
  231. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "DateTime", exception));
  232. }
  233. catch (FormatException exception)
  234. {
  235. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "DateTime", exception));
  236. }
  237. }
  238. static public DateTime ToDateTime(byte[] buffer, int offset, int count)
  239. {
  240. DateTime value;
  241. if (TryParseDateTime(buffer, offset, count, out value))
  242. return value;
  243. return ToDateTime(ToString(buffer, offset, count));
  244. }
  245. static public UniqueId ToUniqueId(string value)
  246. {
  247. try
  248. {
  249. return new UniqueId(Trim(value));
  250. }
  251. catch (ArgumentException exception)
  252. {
  253. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "UniqueId", exception));
  254. }
  255. catch (FormatException exception)
  256. {
  257. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "UniqueId", exception));
  258. }
  259. }
  260. static public UniqueId ToUniqueId(byte[] buffer, int offset, int count)
  261. {
  262. return ToUniqueId(ToString(buffer, offset, count));
  263. }
  264. static public TimeSpan ToTimeSpan(string value)
  265. {
  266. try
  267. {
  268. return XmlConvert.ToTimeSpan(value);
  269. }
  270. catch (ArgumentException exception)
  271. {
  272. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "TimeSpan", exception));
  273. }
  274. catch (FormatException exception)
  275. {
  276. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "TimeSpan", exception));
  277. }
  278. catch (OverflowException exception)
  279. {
  280. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "TimeSpan", exception));
  281. }
  282. }
  283. static public TimeSpan ToTimeSpan(byte[] buffer, int offset, int count)
  284. {
  285. return ToTimeSpan(ToString(buffer, offset, count));
  286. }
  287. [SuppressMessage("Reliability", "Reliability113", Justification = "Catching expected exceptions inline instead of calling Fx.CreateGuid to minimize code change")]
  288. static public Guid ToGuid(string value)
  289. {
  290. try
  291. {
  292. return Guid.Parse(Trim(value));
  293. }
  294. catch (FormatException exception)
  295. {
  296. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "Guid", exception));
  297. }
  298. catch (ArgumentException exception)
  299. {
  300. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "Guid", exception));
  301. }
  302. catch (OverflowException exception)
  303. {
  304. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "Guid", exception));
  305. }
  306. }
  307. static public Guid ToGuid(byte[] buffer, int offset, int count)
  308. {
  309. return ToGuid(ToString(buffer, offset, count));
  310. }
  311. static public UInt64 ToUInt64(string value)
  312. {
  313. try
  314. {
  315. return ulong.Parse(value, NumberFormatInfo.InvariantInfo);
  316. }
  317. catch (ArgumentException exception)
  318. {
  319. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "UInt64", exception));
  320. }
  321. catch (FormatException exception)
  322. {
  323. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "UInt64", exception));
  324. }
  325. catch (OverflowException exception)
  326. {
  327. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateConversionException(value, "UInt64", exception));
  328. }
  329. }
  330. static public UInt64 ToUInt64(byte[] buffer, int offset, int count)
  331. {
  332. return ToUInt64(ToString(buffer, offset, count));
  333. }
  334. static public string ToString(byte[] buffer, int offset, int count)
  335. {
  336. try
  337. {
  338. return UTF8Encoding.GetString(buffer, offset, count);
  339. }
  340. catch (DecoderFallbackException exception)
  341. {
  342. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateEncodingException(buffer, offset, count, exception));
  343. }
  344. }
  345. static public string ToStringUnicode(byte[] buffer, int offset, int count)
  346. {
  347. try
  348. {
  349. return UnicodeEncoding.GetString(buffer, offset, count);
  350. }
  351. catch (DecoderFallbackException exception)
  352. {
  353. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateEncodingException(buffer, offset, count, exception));
  354. }
  355. }
  356. static public byte[] ToBytes(string value)
  357. {
  358. try
  359. {
  360. return UTF8Encoding.GetBytes(value);
  361. }
  362. catch (DecoderFallbackException exception)
  363. {
  364. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateEncodingException(value, exception));
  365. }
  366. }
  367. static public int ToChars(byte[] buffer, int offset, int count, char[] chars, int charOffset)
  368. {
  369. try
  370. {
  371. return UTF8Encoding.GetChars(buffer, offset, count, chars, charOffset);
  372. }
  373. catch (DecoderFallbackException exception)
  374. {
  375. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateEncodingException(buffer, offset, count, exception));
  376. }
  377. }
  378. static public string ToString(bool value) { return value ? "true" : "false"; }
  379. static public string ToString(int value) { return XmlConvert.ToString(value); }
  380. static public string ToString(Int64 value) { return XmlConvert.ToString(value); }
  381. static public string ToString(float value) { return XmlConvert.ToString(value); }
  382. static public string ToString(double value) { return XmlConvert.ToString(value); }
  383. static public string ToString(decimal value) { return XmlConvert.ToString(value); }
  384. static public string ToString(TimeSpan value) { return XmlConvert.ToString(value); }
  385. static public string ToString(UniqueId value) { return value.ToString(); }
  386. static public string ToString(Guid value) { return value.ToString(); }
  387. static public string ToString(UInt64 value) { return value.ToString(NumberFormatInfo.InvariantInfo); }
  388. static public string ToString(DateTime value)
  389. {
  390. byte[] dateChars = new byte[MaxDateTimeChars];
  391. int count = ToChars(value, dateChars, 0);
  392. return ToString(dateChars, 0, count);
  393. }
  394. static string ToString(object value)
  395. {
  396. if (value is int)
  397. return ToString((int)value);
  398. else if (value is Int64)
  399. return ToString((Int64)value);
  400. else if (value is float)
  401. return ToString((float)value);
  402. else if (value is double)
  403. return ToString((double)value);
  404. else if (value is decimal)
  405. return ToString((decimal)value);
  406. else if (value is TimeSpan)
  407. return ToString((TimeSpan)value);
  408. else if (value is UniqueId)
  409. return ToString((UniqueId)value);
  410. else if (value is Guid)
  411. return ToString((Guid)value);
  412. else if (value is UInt64)
  413. return ToString((UInt64)value);
  414. else if (value is DateTime)
  415. return ToString((DateTime)value);
  416. else if (value is bool)
  417. return ToString((bool)value);
  418. else
  419. return value.ToString();
  420. }
  421. static public string ToString(object[] objects)
  422. {
  423. if (objects.Length == 0)
  424. return string.Empty;
  425. string value = ToString(objects[0]);
  426. if (objects.Length > 1)
  427. {
  428. StringBuilder sb = new StringBuilder(value);
  429. for (int i = 1; i < objects.Length; i++)
  430. {
  431. sb.Append(' ');
  432. sb.Append(ToString(objects[i]));
  433. }
  434. value = sb.ToString();
  435. }
  436. return value;
  437. }
  438. static public void ToQualifiedName(string qname, out string prefix, out string localName)
  439. {
  440. int index = qname.IndexOf(':');
  441. if (index < 0)
  442. {
  443. prefix = string.Empty;
  444. localName = Trim(qname);
  445. }
  446. else
  447. {
  448. if (index == qname.Length - 1)
  449. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.XmlInvalidQualifiedName, qname)));
  450. prefix = Trim(qname.Substring(0, index));
  451. localName = Trim(qname.Substring(index + 1));
  452. }
  453. }
  454. static bool TryParseInt32(byte[] chars, int offset, int count, out int result)
  455. {
  456. result = 0;
  457. if (count == 0)
  458. return false;
  459. int value = 0;
  460. int offsetMax = offset + count;
  461. if (chars[offset] == '-')
  462. {
  463. if (count == 1)
  464. return false;
  465. for (int i = offset + 1; i < offsetMax; i++)
  466. {
  467. int digit = (chars[i] - '0');
  468. if ((uint)digit > 9)
  469. return false;
  470. if (value < int.MinValue / 10)
  471. return false;
  472. value *= 10;
  473. if (value < int.MinValue + digit)
  474. return false;
  475. value -= digit;
  476. }
  477. }
  478. else
  479. {
  480. for (int i = offset; i < offsetMax; i++)
  481. {
  482. int digit = (chars[i] - '0');
  483. if ((uint)digit > 9)
  484. return false;
  485. if (value > int.MaxValue / 10)
  486. return false;
  487. value *= 10;
  488. if (value > int.MaxValue - digit)
  489. return false;
  490. value += digit;
  491. }
  492. }
  493. result = value;
  494. return true;
  495. }
  496. static bool TryParseInt64(byte[] chars, int offset, int count, out long result)
  497. {
  498. result = 0;
  499. if (count < 11)
  500. {
  501. int value;
  502. if (!TryParseInt32(chars, offset, count, out value))
  503. return false;
  504. result = value;
  505. return true;
  506. }
  507. else
  508. {
  509. long value = 0;
  510. int offsetMax = offset + count;
  511. if (chars[offset] == '-')
  512. {
  513. if (count == 1)
  514. return false;
  515. for (int i = offset + 1; i < offsetMax; i++)
  516. {
  517. int digit = (chars[i] - '0');
  518. if ((uint)digit > 9)
  519. return false;
  520. if (value < long.MinValue / 10)
  521. return false;
  522. value *= 10;
  523. if (value < long.MinValue + digit)
  524. return false;
  525. value -= digit;
  526. }
  527. }
  528. else
  529. {
  530. for (int i = offset; i < offsetMax; i++)
  531. {
  532. int digit = (chars[i] - '0');
  533. if ((uint)digit > 9)
  534. return false;
  535. if (value > long.MaxValue / 10)
  536. return false;
  537. value *= 10;
  538. if (value > long.MaxValue - digit)
  539. return false;
  540. value += digit;
  541. }
  542. }
  543. result = value;
  544. return true;
  545. }
  546. }
  547. static bool TryParseSingle(byte[] chars, int offset, int count, out float result)
  548. {
  549. result = 0;
  550. int offsetMax = offset + count;
  551. bool negative = false;
  552. if (offset < offsetMax && chars[offset] == '-')
  553. {
  554. negative = true;
  555. offset++;
  556. count--;
  557. }
  558. if (count < 1 || count > 10)
  559. return false;
  560. int value = 0;
  561. int ch;
  562. while (offset < offsetMax)
  563. {
  564. ch = (chars[offset] - '0');
  565. if (ch == ('.' - '0'))
  566. {
  567. offset++;
  568. int pow10 = 1;
  569. while (offset < offsetMax)
  570. {
  571. ch = chars[offset] - '0';
  572. if (((uint)ch) >= 10)
  573. return false;
  574. pow10 *= 10;
  575. value = value * 10 + ch;
  576. offset++;
  577. }
  578. // More than 8 characters (7 sig figs and a decimal) and int -> float conversion is lossy, so use double
  579. if (count > 8)
  580. {
  581. result = (float)((double)value / (double)pow10);
  582. }
  583. else
  584. {
  585. result = (float)value / (float)pow10;
  586. }
  587. if (negative)
  588. result = -result;
  589. return true;
  590. }
  591. else if (((uint)ch) >= 10)
  592. return false;
  593. value = value * 10 + ch;
  594. offset++;
  595. }
  596. // Ten digits w/out a decimal point might've overflowed the int
  597. if (count == 10)
  598. return false;
  599. if (negative)
  600. result = -value;
  601. else
  602. result = value;
  603. return true;
  604. }
  605. static bool TryParseDouble(byte[] chars, int offset, int count, out double result)
  606. {
  607. result = 0;
  608. int offsetMax = offset + count;
  609. bool negative = false;
  610. if (offset < offsetMax && chars[offset] == '-')
  611. {
  612. negative = true;
  613. offset++;
  614. count--;
  615. }
  616. if (count < 1 || count > 10)
  617. return false;
  618. int value = 0;
  619. int ch;
  620. while (offset < offsetMax)
  621. {
  622. ch = (chars[offset] - '0');
  623. if (ch == ('.' - '0'))
  624. {
  625. offset++;
  626. int pow10 = 1;
  627. while (offset < offsetMax)
  628. {
  629. ch = chars[offset] - '0';
  630. if (((uint)ch) >= 10)
  631. return false;
  632. pow10 *= 10;
  633. value = value * 10 + ch;
  634. offset++;
  635. }
  636. if (negative)
  637. result = -(double)value / pow10;
  638. else
  639. result = (double)value / pow10;
  640. return true;
  641. }
  642. else if (((uint)ch) >= 10)
  643. return false;
  644. value = value * 10 + ch;
  645. offset++;
  646. }
  647. // Ten digits w/out a decimal point might've overflowed the int
  648. if (count == 10)
  649. return false;
  650. if (negative)
  651. result = -value;
  652. else
  653. result = value;
  654. return true;
  655. }
  656. static int ToInt32D2(byte[] chars, int offset)
  657. {
  658. byte ch1 = (byte)(chars[offset + 0] - '0');
  659. byte ch2 = (byte)(chars[offset + 1] - '0');
  660. if (ch1 > 9 || ch2 > 9)
  661. return -1;
  662. return 10 * ch1 + ch2;
  663. }
  664. static int ToInt32D4(byte[] chars, int offset, int count)
  665. {
  666. return ToInt32D7(chars, offset, count);
  667. }
  668. static int ToInt32D7(byte[] chars, int offset, int count)
  669. {
  670. int value = 0;
  671. for (int i = 0; i < count; i++)
  672. {
  673. byte ch = (byte)(chars[offset + i] - '0');
  674. if (ch > 9)
  675. return -1;
  676. value = value * 10 + ch;
  677. }
  678. return value;
  679. }
  680. static bool TryParseDateTime(byte[] chars, int offset, int count, out DateTime result)
  681. {
  682. int offsetMax = offset + count;
  683. result = DateTime.MaxValue;
  684. if (count < 19)
  685. return false;
  686. // 1 2 3
  687. // 012345678901234567890123456789012
  688. // "yyyy-MM-ddTHH:mm:ss"
  689. // "yyyy-MM-ddTHH:mm:ss.fffffff"
  690. // "yyyy-MM-ddTHH:mm:ss.fffffffZ"
  691. // "yyyy-MM-ddTHH:mm:ss.fffffff+xx:yy"
  692. // "yyyy-MM-ddTHH:mm:ss.fffffff-xx:yy"
  693. if (chars[offset + 4] != '-' || chars[offset + 7] != '-' || chars[offset + 10] != 'T' ||
  694. chars[offset + 13] != ':' || chars[offset + 16] != ':')
  695. return false;
  696. int year = ToInt32D4(chars, offset + 0, 4);
  697. int month = ToInt32D2(chars, offset + 5);
  698. int day = ToInt32D2(chars, offset + 8);
  699. int hour = ToInt32D2(chars, offset + 11);
  700. int minute = ToInt32D2(chars, offset + 14);
  701. int second = ToInt32D2(chars, offset + 17);
  702. if ((year | month | day | hour | minute | second) < 0)
  703. return false;
  704. DateTimeKind kind = DateTimeKind.Unspecified;
  705. offset += 19;
  706. int ticks = 0;
  707. if (offset < offsetMax && chars[offset] == '.')
  708. {
  709. offset++;
  710. int digitOffset = offset;
  711. while (offset < offsetMax)
  712. {
  713. byte ch = chars[offset];
  714. if (ch < '0' || ch > '9')
  715. break;
  716. offset++;
  717. }
  718. int digitCount = offset - digitOffset;
  719. if (digitCount < 1 || digitCount > 7)
  720. return false;
  721. ticks = ToInt32D7(chars, digitOffset, digitCount);
  722. if (ticks < 0)
  723. return false;
  724. for (int i = digitCount; i < 7; ++i)
  725. ticks *= 10;
  726. }
  727. bool isLocal = false;
  728. int hourDelta = 0;
  729. int minuteDelta = 0;
  730. if (offset < offsetMax)
  731. {
  732. byte ch = chars[offset];
  733. if (ch == 'Z')
  734. {
  735. offset++;
  736. kind = DateTimeKind.Utc;
  737. }
  738. else if (ch == '+' || ch == '-')
  739. {
  740. offset++;
  741. if (offset + 5 > offsetMax || chars[offset + 2] != ':')
  742. return false;
  743. kind = DateTimeKind.Utc;
  744. isLocal = true;
  745. hourDelta = ToInt32D2(chars, offset);
  746. minuteDelta = ToInt32D2(chars, offset + 3);
  747. if ((hourDelta | minuteDelta) < 0)
  748. return false;
  749. if (ch == '+')
  750. {
  751. hourDelta = -hourDelta;
  752. minuteDelta = -minuteDelta;
  753. }
  754. offset += 5;
  755. }
  756. }
  757. if (offset < offsetMax)
  758. return false;
  759. DateTime value;
  760. try
  761. {
  762. value = new DateTime(year, month, day, hour, minute, second, kind);
  763. }
  764. catch (ArgumentException)
  765. {
  766. return false;
  767. }
  768. if (ticks > 0)
  769. {
  770. value = value.AddTicks(ticks);
  771. }
  772. if (isLocal)
  773. {
  774. try
  775. {
  776. TimeSpan ts = new TimeSpan(hourDelta, minuteDelta, 0);
  777. if (hourDelta >= 0 && (value < DateTime.MaxValue - ts) ||
  778. hourDelta < 0 && (value > DateTime.MinValue - ts))
  779. {
  780. value = value.Add(ts).ToLocalTime();
  781. }
  782. else
  783. {
  784. value = value.ToLocalTime().Add(ts);
  785. }
  786. }
  787. catch (ArgumentOutOfRangeException) // Overflow
  788. {
  789. return false;
  790. }
  791. }
  792. result = value;
  793. return true;
  794. }
  795. static public int ToChars(bool value, byte[] buffer, int offset)
  796. {
  797. if (value)
  798. {
  799. buffer[offset + 0] = (byte)'t';
  800. buffer[offset + 1] = (byte)'r';
  801. buffer[offset + 2] = (byte)'u';
  802. buffer[offset + 3] = (byte)'e';
  803. return 4;
  804. }
  805. else
  806. {
  807. buffer[offset + 0] = (byte)'f';
  808. buffer[offset + 1] = (byte)'a';
  809. buffer[offset + 2] = (byte)'l';
  810. buffer[offset + 3] = (byte)'s';
  811. buffer[offset + 4] = (byte)'e';
  812. return 5;
  813. }
  814. }
  815. // Works left from offset
  816. static public int ToCharsR(int value, byte[] chars, int offset)
  817. {
  818. int count = 0;
  819. if (value >= 0)
  820. {
  821. while (value >= 10)
  822. {
  823. int valueDiv10 = value / 10;
  824. count++;
  825. chars[--offset] = (byte)('0' + (value - valueDiv10 * 10));
  826. value = valueDiv10;
  827. }
  828. chars[--offset] = (byte)('0' + value);
  829. count++;
  830. }
  831. else
  832. {
  833. while (value <= -10)
  834. {
  835. int valueDiv10 = value / 10;
  836. count++;
  837. chars[--offset] = (byte)('0' - (value - valueDiv10 * 10));
  838. value = valueDiv10;
  839. }
  840. chars[--offset] = (byte)('0' - value);
  841. chars[--offset] = (byte)'-';
  842. count += 2;
  843. }
  844. return count;
  845. }
  846. static public int ToChars(int value, byte[] chars, int offset)
  847. {
  848. int count = ToCharsR(value, chars, offset + MaxInt32Chars);
  849. Buffer.BlockCopy(chars, offset + MaxInt32Chars - count, chars, offset, count);
  850. return count;
  851. }
  852. static public int ToCharsR(long value, byte[] chars, int offset)
  853. {
  854. int count = 0;
  855. if (value >= 0)
  856. {
  857. while (value > int.MaxValue)
  858. {
  859. long valueDiv10 = value / 10;
  860. count++;
  861. chars[--offset] = (byte)('0' + (int)(value - valueDiv10 * 10));
  862. value = valueDiv10;
  863. }
  864. }
  865. else
  866. {
  867. while (value < int.MinValue)
  868. {
  869. long valueDiv10 = value / 10;
  870. count++;
  871. chars[--offset] = (byte)('0' - (int)(value - valueDiv10 * 10));
  872. value = valueDiv10;
  873. }
  874. }
  875. Fx.Assert(value >= int.MinValue && value <= int.MaxValue, "");
  876. return count + ToCharsR((int)value, chars, offset);
  877. }
  878. static public int ToChars(long value, byte[] chars, int offset)
  879. {
  880. int count = ToCharsR(value, chars, offset + MaxInt64Chars);
  881. Buffer.BlockCopy(chars, offset + MaxInt64Chars - count, chars, offset, count);
  882. return count;
  883. }
  884. [Fx.Tag.SecurityNote(Critical = "Contains unsafe code.",
  885. Safe = "Unsafe code is effectively encapsulated, all inputs are validated.")]
  886. [SecuritySafeCritical]
  887. static unsafe bool IsNegativeZero(float value)
  888. {
  889. // Simple equals function will report that -0 is equal to +0, so compare bits instead
  890. float negativeZero = -0e0F;
  891. return (*(Int32*)&value == *(Int32*)&negativeZero);
  892. }
  893. [Fx.Tag.SecurityNote(Critical = "Contains unsafe code.",
  894. Safe = "Unsafe code is effectively encapsulated, all inputs are validated.")]
  895. [SecuritySafeCritical]
  896. static unsafe bool IsNegativeZero(double value)
  897. {
  898. // Simple equals function will report that -0 is equal to +0, so compare bits instead
  899. double negativeZero = -0e0;
  900. return (*(Int64*)&value == *(Int64*)&negativeZero);
  901. }
  902. static int ToInfinity(bool isNegative, byte[] buffer, int offset)
  903. {
  904. if (isNegative)
  905. {
  906. buffer[offset + 0] = (byte)'-';
  907. buffer[offset + 1] = (byte)'I';
  908. buffer[offset + 2] = (byte)'N';
  909. buffer[offset + 3] = (byte)'F';
  910. return 4;
  911. }
  912. else
  913. {
  914. buffer[offset + 0] = (byte)'I';
  915. buffer[offset + 1] = (byte)'N';
  916. buffer[offset + 2] = (byte)'F';
  917. return 3;
  918. }
  919. }
  920. static int ToZero(bool isNegative, byte[] buffer, int offset)
  921. {
  922. if (isNegative)
  923. {
  924. buffer[offset + 0] = (byte)'-';
  925. buffer[offset + 1] = (byte)'0';
  926. return 2;
  927. }
  928. else
  929. {
  930. buffer[offset] = (byte)'0';
  931. return 1;
  932. }
  933. }
  934. static public int ToChars(double value, byte[] buffer, int offset)
  935. {
  936. if (double.IsInfinity(value))
  937. return ToInfinity(double.IsNegativeInfinity(value), buffer, offset);
  938. if (value == 0.0)
  939. return ToZero(IsNegativeZero(value), buffer, offset);
  940. return ToAsciiChars(value.ToString("R", NumberFormatInfo.InvariantInfo), buffer, offset);
  941. }
  942. static public int ToChars(float value, byte[] buffer, int offset)
  943. {
  944. if (float.IsInfinity(value))
  945. return ToInfinity(float.IsNegativeInfinity(value), buffer, offset);
  946. if (value == 0.0)
  947. return ToZero(IsNegativeZero(value), buffer, offset);
  948. return ToAsciiChars(value.ToString("R", NumberFormatInfo.InvariantInfo), buffer, offset);
  949. }
  950. static public int ToChars(decimal value, byte[] buffer, int offset)
  951. {
  952. return ToAsciiChars(value.ToString(null, NumberFormatInfo.InvariantInfo), buffer, offset);
  953. }
  954. static public int ToChars(UInt64 value, byte[] buffer, int offset)
  955. {
  956. return ToAsciiChars(value.ToString(null, NumberFormatInfo.InvariantInfo), buffer, offset);
  957. }
  958. static int ToAsciiChars(string s, byte[] buffer, int offset)
  959. {
  960. for (int i = 0; i < s.Length; i++)
  961. {
  962. Fx.Assert(s[i] < 128, "");
  963. buffer[offset++] = (byte)s[i];
  964. }
  965. return s.Length;
  966. }
  967. static int ToCharsD2(int value, byte[] chars, int offset)
  968. {
  969. Fx.Assert(value >= 0 && value < 100, "");
  970. if (value < 10)
  971. {
  972. chars[offset + 0] = (byte)'0';
  973. chars[offset + 1] = (byte)('0' + value);
  974. }
  975. else
  976. {
  977. int valueDiv10 = value / 10;
  978. chars[offset + 0] = (byte)('0' + valueDiv10);
  979. chars[offset + 1] = (byte)('0' + value - valueDiv10 * 10);
  980. }
  981. return 2;
  982. }
  983. static int ToCharsD4(int value, byte[] chars, int offset)
  984. {
  985. Fx.Assert(value >= 0 && value < 10000, "");
  986. ToCharsD2(value / 100, chars, offset + 0);
  987. ToCharsD2(value % 100, chars, offset + 2);
  988. return 4;
  989. }
  990. static int ToCharsD7(int value, byte[] chars, int offset)
  991. {
  992. Fx.Assert(value >= 0 && value < 10000000, "");
  993. int zeroCount = 7 - ToCharsR(value, chars, offset + 7);
  994. for (int i = 0; i < zeroCount; i++)
  995. chars[offset + i] = (byte)'0';
  996. int count = 7;
  997. while (count > 0 && chars[offset + count - 1] == '0')
  998. count--;
  999. return count;
  1000. }
  1001. static public int ToChars(DateTime value, byte[] chars, int offset)
  1002. {
  1003. const long TicksPerMillisecond = 10000;
  1004. const long TicksPerSecond = TicksPerMillisecond * 1000;
  1005. int offsetMin = offset;
  1006. // "yyyy-MM-ddTHH:mm:ss.fffffff";
  1007. offset += ToCharsD4(value.Year, chars, offset);
  1008. chars[offset++] = (byte)'-';
  1009. offset += ToCharsD2(value.Month, chars, offset);
  1010. chars[offset++] = (byte)'-';
  1011. offset += ToCharsD2(value.Day, chars, offset);
  1012. chars[offset++] = (byte)'T';
  1013. offset += ToCharsD2(value.Hour, chars, offset);
  1014. chars[offset++] = (byte)':';
  1015. offset += ToCharsD2(value.Minute, chars, offset);
  1016. chars[offset++] = (byte)':';
  1017. offset += ToCharsD2(value.Second, chars, offset);
  1018. int ms = (int)(value.Ticks % TicksPerSecond);
  1019. if (ms != 0)
  1020. {
  1021. chars[offset++] = (byte)'.';
  1022. offset += ToCharsD7(ms, chars, offset);
  1023. }
  1024. switch (value.Kind)
  1025. {
  1026. case DateTimeKind.Unspecified:
  1027. break;
  1028. case DateTimeKind.Local:
  1029. // +"zzzzzz";
  1030. TimeSpan ts = TimeZoneInfo.Local.GetUtcOffset(value);
  1031. if (ts.Ticks < 0)
  1032. chars[offset++] = (byte)'-';
  1033. else
  1034. chars[offset++] = (byte)'+';
  1035. offset += ToCharsD2(Math.Abs(ts.Hours), chars, offset);
  1036. chars[offset++] = (byte)':';
  1037. offset += ToCharsD2(Math.Abs(ts.Minutes), chars, offset);
  1038. break;
  1039. case DateTimeKind.Utc:
  1040. // +"Z"
  1041. chars[offset++] = (byte)'Z';
  1042. break;
  1043. default:
  1044. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException());
  1045. }
  1046. return offset - offsetMin;
  1047. }
  1048. static public bool IsWhitespace(string s)
  1049. {
  1050. for (int i = 0; i < s.Length; i++)
  1051. {
  1052. if (!IsWhitespace(s[i]))
  1053. return false;
  1054. }
  1055. return true;
  1056. }
  1057. static public bool IsWhitespace(char ch)
  1058. {
  1059. return (ch <= ' ' && (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n'));
  1060. }
  1061. static public string StripWhitespace(string s)
  1062. {
  1063. int count = s.Length;
  1064. for (int i = 0; i < s.Length; i++)
  1065. {
  1066. if (IsWhitespace(s[i]))
  1067. {
  1068. count--;
  1069. }
  1070. }
  1071. if (count == s.Length)
  1072. return s;
  1073. char[] chars = new char[count];
  1074. count = 0;
  1075. for (int i = 0; i < s.Length; i++)
  1076. {
  1077. char ch = s[i];
  1078. if (!IsWhitespace(ch))
  1079. {
  1080. chars[count++] = ch;
  1081. }
  1082. }
  1083. return new string(chars);
  1084. }
  1085. static string Trim(string s)
  1086. {
  1087. int i;
  1088. for (i = 0; i < s.Length && IsWhitespace(s[i]); i++);
  1089. int j;
  1090. for (j = s.Length; j > 0 && IsWhitespace(s[j - 1]); j--);
  1091. if (i == 0 && j == s.Length)
  1092. return s;
  1093. else if (j == 0)
  1094. return string.Empty;
  1095. else
  1096. return s.Substring(i, j - i);
  1097. }
  1098. }
  1099. }