Base64Encoding.cs 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //-----------------------------------------------------------------------------
  4. namespace System.Text
  5. {
  6. using System.Globalization;
  7. using System.Runtime;
  8. using System.Runtime.Serialization; //For SR
  9. using System.Security;
  10. class Base64Encoding : Encoding
  11. {
  12. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.StyleCop.CSharp.SpacingRules", "SA1025:CodeMustNotContainMultipleWhitespaceInARow", Justification = "This alignment is optimal.")]
  13. static byte[] char2val = new byte[128]
  14. {
  15. /* 0-15 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  16. /* 16-31 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  17. /* 32-47 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 62, 0xFF, 0xFF, 0xFF, 63,
  18. /* 48-63 */ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0xFF, 0xFF, 0xFF, 64, 0xFF, 0xFF,
  19. /* 64-79 */ 0xFF, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
  20. /* 80-95 */ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  21. /* 96-111 */ 0xFF, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
  22. /* 112-127 */ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  23. };
  24. static string val2char = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  25. static byte[] val2byte = new byte[]
  26. {
  27. (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G', (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N', (byte)'O', (byte)'P',
  28. (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U', (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z', (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f',
  29. (byte)'g', (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n', (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u', (byte)'v',
  30. (byte)'w', (byte)'x', (byte)'y', (byte)'z', (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', (byte)'7', (byte)'8', (byte)'9', (byte)'+', (byte)'/'
  31. };
  32. public override int GetMaxByteCount(int charCount)
  33. {
  34. if (charCount < 0)
  35. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("charCount", SR.GetString(SR.ValueMustBeNonNegative)));
  36. if ((charCount % 4) != 0)
  37. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(SR.GetString(SR.XmlInvalidBase64Length, charCount.ToString(NumberFormatInfo.CurrentInfo))));
  38. return charCount / 4 * 3;
  39. }
  40. bool IsValidLeadBytes(int v1, int v2, int v3, int v4)
  41. {
  42. // First two chars of a four char base64 sequence can't be ==, and must be valid
  43. return ((v1 | v2) < 64) && ((v3 | v4) != 0xFF);
  44. }
  45. bool IsValidTailBytes(int v3, int v4)
  46. {
  47. // If the third char is = then the fourth char must be =
  48. return !(v3 == 64 && v4 != 64);
  49. }
  50. [Fx.Tag.SecurityNote(Critical = "Contains unsafe code.",
  51. Safe = "Unsafe code is effectively encapsulated, all inputs are validated.")]
  52. [SecuritySafeCritical]
  53. unsafe public override int GetByteCount(char[] chars, int index, int count)
  54. {
  55. if (chars == null)
  56. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("chars"));
  57. if (index < 0)
  58. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("index", SR.GetString(SR.ValueMustBeNonNegative)));
  59. if (index > chars.Length)
  60. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("index", SR.GetString(SR.OffsetExceedsBufferSize, chars.Length)));
  61. if (count < 0)
  62. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("count", SR.GetString(SR.ValueMustBeNonNegative)));
  63. if (count > chars.Length - index)
  64. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("count", SR.GetString(SR.SizeExceedsRemainingBufferSpace, chars.Length - index)));
  65. if (count == 0)
  66. return 0;
  67. if ((count % 4) != 0)
  68. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(SR.GetString(SR.XmlInvalidBase64Length, count.ToString(NumberFormatInfo.CurrentInfo))));
  69. fixed (byte* _char2val = char2val)
  70. {
  71. fixed (char* _chars = &chars[index])
  72. {
  73. int totalCount = 0;
  74. char* pch = _chars;
  75. char* pchMax = _chars + count;
  76. while (pch < pchMax)
  77. {
  78. Fx.Assert(pch + 4 <= pchMax, "");
  79. char pch0 = pch[0];
  80. char pch1 = pch[1];
  81. char pch2 = pch[2];
  82. char pch3 = pch[3];
  83. if ((pch0 | pch1 | pch2 | pch3) >= 128)
  84. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(SR.GetString(SR.XmlInvalidBase64Sequence, new string(pch, 0, 4), index + (int)(pch - _chars))));
  85. // xx765432 xx107654 xx321076 xx543210
  86. // 76543210 76543210 76543210
  87. int v1 = _char2val[pch0];
  88. int v2 = _char2val[pch1];
  89. int v3 = _char2val[pch2];
  90. int v4 = _char2val[pch3];
  91. if (!IsValidLeadBytes(v1, v2, v3, v4) || !IsValidTailBytes(v3, v4))
  92. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(SR.GetString(SR.XmlInvalidBase64Sequence, new string(pch, 0, 4), index + (int)(pch - _chars))));
  93. int byteCount = (v4 != 64 ? 3 : (v3 != 64 ? 2 : 1));
  94. totalCount += byteCount;
  95. pch += 4;
  96. }
  97. return totalCount;
  98. }
  99. }
  100. }
  101. [Fx.Tag.SecurityNote(Critical = "Contains unsafe code.",
  102. Safe = "Unsafe code is effectively encapsulated, all inputs are validated.")]
  103. [SecuritySafeCritical]
  104. unsafe public override int GetBytes(char[] chars, int charIndex, int charCount, byte[] bytes, int byteIndex)
  105. {
  106. if (chars == null)
  107. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("chars"));
  108. if (charIndex < 0)
  109. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("charIndex", SR.GetString(SR.ValueMustBeNonNegative)));
  110. if (charIndex > chars.Length)
  111. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("charIndex", SR.GetString(SR.OffsetExceedsBufferSize, chars.Length)));
  112. if (charCount < 0)
  113. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("charCount", SR.GetString(SR.ValueMustBeNonNegative)));
  114. if (charCount > chars.Length - charIndex)
  115. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("charCount", SR.GetString(SR.SizeExceedsRemainingBufferSpace, chars.Length - charIndex)));
  116. if (bytes == null)
  117. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("bytes"));
  118. if (byteIndex < 0)
  119. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("byteIndex", SR.GetString(SR.ValueMustBeNonNegative)));
  120. if (byteIndex > bytes.Length)
  121. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("byteIndex", SR.GetString(SR.OffsetExceedsBufferSize, bytes.Length)));
  122. if (charCount == 0)
  123. return 0;
  124. if ((charCount % 4) != 0)
  125. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(SR.GetString(SR.XmlInvalidBase64Length, charCount.ToString(NumberFormatInfo.CurrentInfo))));
  126. fixed (byte* _char2val = char2val)
  127. {
  128. fixed (char* _chars = &chars[charIndex])
  129. {
  130. fixed (byte* _bytes = &bytes[byteIndex])
  131. {
  132. char* pch = _chars;
  133. char* pchMax = _chars + charCount;
  134. byte* pb = _bytes;
  135. byte* pbMax = _bytes + bytes.Length - byteIndex;
  136. while (pch < pchMax)
  137. {
  138. Fx.Assert(pch + 4 <= pchMax, "");
  139. char pch0 = pch[0];
  140. char pch1 = pch[1];
  141. char pch2 = pch[2];
  142. char pch3 = pch[3];
  143. if ((pch0 | pch1 | pch2 | pch3) >= 128)
  144. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(SR.GetString(SR.XmlInvalidBase64Sequence, new string(pch, 0, 4), charIndex + (int)(pch - _chars))));
  145. // xx765432 xx107654 xx321076 xx543210
  146. // 76543210 76543210 76543210
  147. int v1 = _char2val[pch0];
  148. int v2 = _char2val[pch1];
  149. int v3 = _char2val[pch2];
  150. int v4 = _char2val[pch3];
  151. if (!IsValidLeadBytes(v1, v2, v3, v4) || !IsValidTailBytes(v3, v4))
  152. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(SR.GetString(SR.XmlInvalidBase64Sequence, new string(pch, 0, 4), charIndex + (int)(pch - _chars))));
  153. int byteCount = (v4 != 64 ? 3 : (v3 != 64 ? 2 : 1));
  154. if (pb + byteCount > pbMax)
  155. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.XmlArrayTooSmall), "bytes"));
  156. pb[0] = (byte)((v1 << 2) | ((v2 >> 4) & 0x03));
  157. if (byteCount > 1)
  158. {
  159. pb[1] = (byte)((v2 << 4) | ((v3 >> 2) & 0x0F));
  160. if (byteCount > 2)
  161. {
  162. pb[2] = (byte)((v3 << 6) | ((v4 >> 0) & 0x3F));
  163. }
  164. }
  165. pb += byteCount;
  166. pch += 4;
  167. }
  168. return (int)(pb - _bytes);
  169. }
  170. }
  171. }
  172. }
  173. [Fx.Tag.SecurityNote(Critical = "Contains unsafe code.",
  174. Safe = "Unsafe code is effectively encapsulated, all inputs are validated.")]
  175. [SecuritySafeCritical]
  176. unsafe public virtual int GetBytes(byte[] chars, int charIndex, int charCount, byte[] bytes, int byteIndex)
  177. {
  178. if (chars == null)
  179. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("chars"));
  180. if (charIndex < 0)
  181. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("charIndex", SR.GetString(SR.ValueMustBeNonNegative)));
  182. if (charIndex > chars.Length)
  183. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("charIndex", SR.GetString(SR.OffsetExceedsBufferSize, chars.Length)));
  184. if (charCount < 0)
  185. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("charCount", SR.GetString(SR.ValueMustBeNonNegative)));
  186. if (charCount > chars.Length - charIndex)
  187. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("charCount", SR.GetString(SR.SizeExceedsRemainingBufferSpace, chars.Length - charIndex)));
  188. if (bytes == null)
  189. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("bytes"));
  190. if (byteIndex < 0)
  191. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("byteIndex", SR.GetString(SR.ValueMustBeNonNegative)));
  192. if (byteIndex > bytes.Length)
  193. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("byteIndex", SR.GetString(SR.OffsetExceedsBufferSize, bytes.Length)));
  194. if (charCount == 0)
  195. return 0;
  196. if ((charCount % 4) != 0)
  197. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(SR.GetString(SR.XmlInvalidBase64Length, charCount.ToString(NumberFormatInfo.CurrentInfo))));
  198. fixed (byte* _char2val = char2val)
  199. {
  200. fixed (byte* _chars = &chars[charIndex])
  201. {
  202. fixed (byte* _bytes = &bytes[byteIndex])
  203. {
  204. byte* pch = _chars;
  205. byte* pchMax = _chars + charCount;
  206. byte* pb = _bytes;
  207. byte* pbMax = _bytes + bytes.Length - byteIndex;
  208. while (pch < pchMax)
  209. {
  210. Fx.Assert(pch + 4 <= pchMax, "");
  211. byte pch0 = pch[0];
  212. byte pch1 = pch[1];
  213. byte pch2 = pch[2];
  214. byte pch3 = pch[3];
  215. if ((pch0 | pch1 | pch2 | pch3) >= 128)
  216. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(SR.GetString(SR.XmlInvalidBase64Sequence, new string((sbyte*)pch, 0, 4), charIndex + (int)(pch - _chars))));
  217. // xx765432 xx107654 xx321076 xx543210
  218. // 76543210 76543210 76543210
  219. int v1 = _char2val[pch0];
  220. int v2 = _char2val[pch1];
  221. int v3 = _char2val[pch2];
  222. int v4 = _char2val[pch3];
  223. if (!IsValidLeadBytes(v1, v2, v3, v4) || !IsValidTailBytes(v3, v4))
  224. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException(SR.GetString(SR.XmlInvalidBase64Sequence, new string((sbyte*)pch, 0, 4), charIndex + (int)(pch - _chars))));
  225. int byteCount = (v4 != 64 ? 3 : (v3 != 64 ? 2 : 1));
  226. if (pb + byteCount > pbMax)
  227. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.XmlArrayTooSmall), "bytes"));
  228. pb[0] = (byte)((v1 << 2) | ((v2 >> 4) & 0x03));
  229. if (byteCount > 1)
  230. {
  231. pb[1] = (byte)((v2 << 4) | ((v3 >> 2) & 0x0F));
  232. if (byteCount > 2)
  233. {
  234. pb[2] = (byte)((v3 << 6) | ((v4 >> 0) & 0x3F));
  235. }
  236. }
  237. pb += byteCount;
  238. pch += 4;
  239. }
  240. return (int)(pb - _bytes);
  241. }
  242. }
  243. }
  244. }
  245. #if NO
  246. public override Encoder GetEncoder()
  247. {
  248. return new BufferedEncoder(this, 4);
  249. }
  250. public override Decoder GetDecoder()
  251. {
  252. return new BufferedDecoder(this, 3);
  253. }
  254. #endif
  255. public override int GetMaxCharCount(int byteCount)
  256. {
  257. if (byteCount < 0 || byteCount > int.MaxValue / 4 * 3 - 2)
  258. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("byteCount", SR.GetString(SR.ValueMustBeInRange, 0, int.MaxValue / 4 * 3 - 2)));
  259. return ((byteCount + 2) / 3) * 4;
  260. }
  261. public override int GetCharCount(byte[] bytes, int index, int count)
  262. {
  263. return GetMaxCharCount(count);
  264. }
  265. [Fx.Tag.SecurityNote(Critical = "Contains unsafe code.",
  266. Safe = "Unsafe code is effectively encapsulated, all inputs are validated.")]
  267. [SecuritySafeCritical]
  268. unsafe public override int GetChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex)
  269. {
  270. if (bytes == null)
  271. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("bytes"));
  272. if (byteIndex < 0)
  273. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("byteIndex", SR.GetString(SR.ValueMustBeNonNegative)));
  274. if (byteIndex > bytes.Length)
  275. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("byteIndex", SR.GetString(SR.OffsetExceedsBufferSize, bytes.Length)));
  276. if (byteCount < 0)
  277. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("byteCount", SR.GetString(SR.ValueMustBeNonNegative)));
  278. if (byteCount > bytes.Length - byteIndex)
  279. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("byteCount", SR.GetString(SR.SizeExceedsRemainingBufferSpace, bytes.Length - byteIndex)));
  280. int charCount = GetCharCount(bytes, byteIndex, byteCount);
  281. if (chars == null)
  282. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("chars"));
  283. if (charIndex < 0)
  284. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("charIndex", SR.GetString(SR.ValueMustBeNonNegative)));
  285. if (charIndex > chars.Length)
  286. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("charIndex", SR.GetString(SR.OffsetExceedsBufferSize, chars.Length)));
  287. if (charCount < 0 || charCount > chars.Length - charIndex)
  288. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.XmlArrayTooSmall), "chars"));
  289. // We've computed exactly how many chars there are and verified that
  290. // there's enough space in the char buffer, so we can proceed without
  291. // checking the charCount.
  292. if (byteCount > 0)
  293. {
  294. fixed (char* _val2char = val2char)
  295. {
  296. fixed (byte* _bytes = &bytes[byteIndex])
  297. {
  298. fixed (char* _chars = &chars[charIndex])
  299. {
  300. byte* pb = _bytes;
  301. byte* pbMax = pb + byteCount - 3;
  302. char* pch = _chars;
  303. // Convert chunks of 3 bytes to 4 chars
  304. while (pb <= pbMax)
  305. {
  306. // 76543210 76543210 76543210
  307. // xx765432 xx107654 xx321076 xx543210
  308. // Inspect the code carefully before you change this
  309. pch[0] = _val2char[(pb[0] >> 2)];
  310. pch[1] = _val2char[((pb[0] & 0x03) << 4) | (pb[1] >> 4)];
  311. pch[2] = _val2char[((pb[1] & 0x0F) << 2) | (pb[2] >> 6)];
  312. pch[3] = _val2char[pb[2] & 0x3F];
  313. pb += 3;
  314. pch += 4;
  315. }
  316. // Handle 1 or 2 trailing bytes
  317. if (pb - pbMax == 2)
  318. {
  319. // 1 trailing byte
  320. // 76543210 xxxxxxxx xxxxxxxx
  321. // xx765432 xx10xxxx xxxxxxxx xxxxxxxx
  322. pch[0] = _val2char[(pb[0] >> 2)];
  323. pch[1] = _val2char[((pb[0] & 0x03) << 4)];
  324. pch[2] = '=';
  325. pch[3] = '=';
  326. }
  327. else if (pb - pbMax == 1)
  328. {
  329. // 2 trailing bytes
  330. // 76543210 76543210 xxxxxxxx
  331. // xx765432 xx107654 xx3210xx xxxxxxxx
  332. pch[0] = _val2char[(pb[0] >> 2)];
  333. pch[1] = _val2char[((pb[0] & 0x03) << 4) | (pb[1] >> 4)];
  334. pch[2] = _val2char[((pb[1] & 0x0F) << 2)];
  335. pch[3] = '=';
  336. }
  337. else
  338. {
  339. // 0 trailing bytes
  340. Fx.Assert(pb - pbMax == 3, "");
  341. }
  342. }
  343. }
  344. }
  345. }
  346. return charCount;
  347. }
  348. [Fx.Tag.SecurityNote(Critical = "Contains unsafe code.",
  349. Safe = "Unsafe code is effectively encapsulated, all inputs are validated.")]
  350. [SecuritySafeCritical]
  351. unsafe public int GetChars(byte[] bytes, int byteIndex, int byteCount, byte[] chars, int charIndex)
  352. {
  353. if (bytes == null)
  354. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("bytes"));
  355. if (byteIndex < 0)
  356. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("byteIndex", SR.GetString(SR.ValueMustBeNonNegative)));
  357. if (byteIndex > bytes.Length)
  358. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("byteIndex", SR.GetString(SR.OffsetExceedsBufferSize, bytes.Length)));
  359. if (byteCount < 0)
  360. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("byteCount", SR.GetString(SR.ValueMustBeNonNegative)));
  361. if (byteCount > bytes.Length - byteIndex)
  362. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("byteCount", SR.GetString(SR.SizeExceedsRemainingBufferSpace, bytes.Length - byteIndex)));
  363. int charCount = GetCharCount(bytes, byteIndex, byteCount);
  364. if (chars == null)
  365. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("chars"));
  366. if (charIndex < 0)
  367. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("charIndex", SR.GetString(SR.ValueMustBeNonNegative)));
  368. if (charIndex > chars.Length)
  369. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("charIndex", SR.GetString(SR.OffsetExceedsBufferSize, chars.Length)));
  370. if (charCount < 0 || charCount > chars.Length - charIndex)
  371. throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.XmlArrayTooSmall), "chars"));
  372. // We've computed exactly how many chars there are and verified that
  373. // there's enough space in the char buffer, so we can proceed without
  374. // checking the charCount.
  375. if (byteCount > 0)
  376. {
  377. fixed (byte* _val2byte = val2byte)
  378. {
  379. fixed (byte* _bytes = &bytes[byteIndex])
  380. {
  381. fixed (byte* _chars = &chars[charIndex])
  382. {
  383. byte* pb = _bytes;
  384. byte* pbMax = pb + byteCount - 3;
  385. byte* pch = _chars;
  386. // Convert chunks of 3 bytes to 4 chars
  387. while (pb <= pbMax)
  388. {
  389. // 76543210 76543210 76543210
  390. // xx765432 xx107654 xx321076 xx543210
  391. // Inspect the code carefully before you change this
  392. pch[0] = _val2byte[(pb[0] >> 2)];
  393. pch[1] = _val2byte[((pb[0] & 0x03) << 4) | (pb[1] >> 4)];
  394. pch[2] = _val2byte[((pb[1] & 0x0F) << 2) | (pb[2] >> 6)];
  395. pch[3] = _val2byte[pb[2] & 0x3F];
  396. pb += 3;
  397. pch += 4;
  398. }
  399. // Handle 1 or 2 trailing bytes
  400. if (pb - pbMax == 2)
  401. {
  402. // 1 trailing byte
  403. // 76543210 xxxxxxxx xxxxxxxx
  404. // xx765432 xx10xxxx xxxxxxxx xxxxxxxx
  405. pch[0] = _val2byte[(pb[0] >> 2)];
  406. pch[1] = _val2byte[((pb[0] & 0x03) << 4)];
  407. pch[2] = (byte)'=';
  408. pch[3] = (byte)'=';
  409. }
  410. else if (pb - pbMax == 1)
  411. {
  412. // 2 trailing bytes
  413. // 76543210 76543210 xxxxxxxx
  414. // xx765432 xx107654 xx3210xx xxxxxxxx
  415. pch[0] = _val2byte[(pb[0] >> 2)];
  416. pch[1] = _val2byte[((pb[0] & 0x03) << 4) | (pb[1] >> 4)];
  417. pch[2] = _val2byte[((pb[1] & 0x0F) << 2)];
  418. pch[3] = (byte)'=';
  419. }
  420. else
  421. {
  422. // 0 trailing bytes
  423. Fx.Assert(pb - pbMax == 3, "");
  424. }
  425. }
  426. }
  427. }
  428. }
  429. return charCount;
  430. }
  431. }
  432. }