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