1 // Licensed to the .NET Foundation under one or more agreements. 2 // The .NET Foundation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using System.Runtime.Serialization; 6 using System.Diagnostics; 7 using System.Globalization; 8 using System.Text; 9 10 11 namespace System.Xml 12 { 13 internal enum ValueHandleConstStringType 14 { 15 String = 0, 16 Number = 1, 17 Array = 2, 18 Object = 3, 19 Boolean = 4, 20 Null = 5, 21 } 22 23 internal static class ValueHandleLength 24 { 25 public const int Int8 = 1; 26 public const int Int16 = 2; 27 public const int Int32 = 4; 28 public const int Int64 = 8; 29 public const int UInt64 = 8; 30 public const int Single = 4; 31 public const int Double = 8; 32 public const int Decimal = 16; 33 public const int DateTime = 8; 34 public const int TimeSpan = 8; 35 public const int Guid = 16; 36 public const int UniqueId = 16; 37 } 38 39 internal enum ValueHandleType 40 { 41 Empty, 42 True, 43 False, 44 Zero, 45 One, 46 Int8, 47 Int16, 48 Int32, 49 Int64, 50 UInt64, 51 Single, 52 Double, 53 Decimal, 54 DateTime, 55 TimeSpan, 56 Guid, 57 UniqueId, 58 UTF8, 59 EscapedUTF8, 60 Base64, 61 Dictionary, 62 List, 63 Char, 64 Unicode, 65 QName, 66 ConstString 67 } 68 69 internal class ValueHandle 70 { 71 private XmlBufferReader _bufferReader; 72 private ValueHandleType _type; 73 private int _offset; 74 private int _length; 75 private static Base64Encoding s_base64Encoding; 76 private static string[] s_constStrings = { 77 "string", 78 "number", 79 "array", 80 "object", 81 "boolean", 82 "null", 83 }; 84 ValueHandle(XmlBufferReader bufferReader)85 public ValueHandle(XmlBufferReader bufferReader) 86 { 87 _bufferReader = bufferReader; 88 _type = ValueHandleType.Empty; 89 } 90 91 private static Base64Encoding Base64Encoding 92 { 93 get 94 { 95 if (s_base64Encoding == null) 96 s_base64Encoding = new Base64Encoding(); 97 return s_base64Encoding; 98 } 99 } SetConstantValue(ValueHandleConstStringType constStringType)100 public void SetConstantValue(ValueHandleConstStringType constStringType) 101 { 102 _type = ValueHandleType.ConstString; 103 _offset = (int)constStringType; 104 } 105 SetValue(ValueHandleType type)106 public void SetValue(ValueHandleType type) 107 { 108 _type = type; 109 } 110 SetDictionaryValue(int key)111 public void SetDictionaryValue(int key) 112 { 113 SetValue(ValueHandleType.Dictionary, key, 0); 114 } 115 SetCharValue(int ch)116 public void SetCharValue(int ch) 117 { 118 SetValue(ValueHandleType.Char, ch, 0); 119 } 120 SetQNameValue(int prefix, int key)121 public void SetQNameValue(int prefix, int key) 122 { 123 SetValue(ValueHandleType.QName, key, prefix); 124 } SetValue(ValueHandleType type, int offset, int length)125 public void SetValue(ValueHandleType type, int offset, int length) 126 { 127 _type = type; 128 _offset = offset; 129 _length = length; 130 } 131 IsWhitespace()132 public bool IsWhitespace() 133 { 134 switch (_type) 135 { 136 case ValueHandleType.UTF8: 137 return _bufferReader.IsWhitespaceUTF8(_offset, _length); 138 139 case ValueHandleType.Dictionary: 140 return _bufferReader.IsWhitespaceKey(_offset); 141 142 case ValueHandleType.Char: 143 int ch = GetChar(); 144 if (ch > char.MaxValue) 145 return false; 146 return XmlConverter.IsWhitespace((char)ch); 147 148 case ValueHandleType.EscapedUTF8: 149 return _bufferReader.IsWhitespaceUTF8(_offset, _length); 150 151 case ValueHandleType.Unicode: 152 return _bufferReader.IsWhitespaceUnicode(_offset, _length); 153 154 case ValueHandleType.True: 155 case ValueHandleType.False: 156 case ValueHandleType.Zero: 157 case ValueHandleType.One: 158 return false; 159 160 case ValueHandleType.ConstString: 161 return s_constStrings[_offset].Length == 0; 162 163 default: 164 return _length == 0; 165 } 166 } 167 ToType()168 public Type ToType() 169 { 170 switch (_type) 171 { 172 case ValueHandleType.False: 173 case ValueHandleType.True: 174 return typeof(bool); 175 case ValueHandleType.Zero: 176 case ValueHandleType.One: 177 case ValueHandleType.Int8: 178 case ValueHandleType.Int16: 179 case ValueHandleType.Int32: 180 return typeof(int); 181 case ValueHandleType.Int64: 182 return typeof(long); 183 case ValueHandleType.UInt64: 184 return typeof(ulong); 185 case ValueHandleType.Single: 186 return typeof(float); 187 case ValueHandleType.Double: 188 return typeof(double); 189 case ValueHandleType.Decimal: 190 return typeof(decimal); 191 case ValueHandleType.DateTime: 192 return typeof(DateTime); 193 case ValueHandleType.Empty: 194 case ValueHandleType.UTF8: 195 case ValueHandleType.Unicode: 196 case ValueHandleType.EscapedUTF8: 197 case ValueHandleType.Dictionary: 198 case ValueHandleType.Char: 199 case ValueHandleType.QName: 200 case ValueHandleType.ConstString: 201 return typeof(string); 202 case ValueHandleType.Base64: 203 return typeof(byte[]); 204 case ValueHandleType.List: 205 return typeof(object[]); 206 case ValueHandleType.UniqueId: 207 return typeof(UniqueId); 208 case ValueHandleType.Guid: 209 return typeof(Guid); 210 case ValueHandleType.TimeSpan: 211 return typeof(TimeSpan); 212 default: 213 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException()); 214 } 215 } 216 ToBoolean()217 public Boolean ToBoolean() 218 { 219 ValueHandleType type = _type; 220 if (type == ValueHandleType.False) 221 return false; 222 if (type == ValueHandleType.True) 223 return true; 224 if (type == ValueHandleType.UTF8) 225 return XmlConverter.ToBoolean(_bufferReader.Buffer, _offset, _length); 226 if (type == ValueHandleType.Int8) 227 { 228 int value = GetInt8(); 229 if (value == 0) 230 return false; 231 if (value == 1) 232 return true; 233 } 234 return XmlConverter.ToBoolean(GetString()); 235 } 236 ToInt()237 public int ToInt() 238 { 239 ValueHandleType type = _type; 240 if (type == ValueHandleType.Zero) 241 return 0; 242 if (type == ValueHandleType.One) 243 return 1; 244 if (type == ValueHandleType.Int8) 245 return GetInt8(); 246 if (type == ValueHandleType.Int16) 247 return GetInt16(); 248 if (type == ValueHandleType.Int32) 249 return GetInt32(); 250 if (type == ValueHandleType.Int64) 251 { 252 long value = GetInt64(); 253 if (value >= int.MinValue && value <= int.MaxValue) 254 { 255 return (int)value; 256 } 257 } 258 if (type == ValueHandleType.UInt64) 259 { 260 ulong value = GetUInt64(); 261 if (value <= int.MaxValue) 262 { 263 return (int)value; 264 } 265 } 266 if (type == ValueHandleType.UTF8) 267 return XmlConverter.ToInt32(_bufferReader.Buffer, _offset, _length); 268 return XmlConverter.ToInt32(GetString()); 269 } 270 ToLong()271 public long ToLong() 272 { 273 ValueHandleType type = _type; 274 if (type == ValueHandleType.Zero) 275 return 0; 276 if (type == ValueHandleType.One) 277 return 1; 278 if (type == ValueHandleType.Int8) 279 return GetInt8(); 280 if (type == ValueHandleType.Int16) 281 return GetInt16(); 282 if (type == ValueHandleType.Int32) 283 return GetInt32(); 284 if (type == ValueHandleType.Int64) 285 return GetInt64(); 286 if (type == ValueHandleType.UInt64) 287 { 288 ulong value = GetUInt64(); 289 if (value <= long.MaxValue) 290 { 291 return (long)value; 292 } 293 } 294 if (type == ValueHandleType.UTF8) 295 { 296 return XmlConverter.ToInt64(_bufferReader.Buffer, _offset, _length); 297 } 298 return XmlConverter.ToInt64(GetString()); 299 } 300 ToULong()301 public ulong ToULong() 302 { 303 ValueHandleType type = _type; 304 if (type == ValueHandleType.Zero) 305 return 0; 306 if (type == ValueHandleType.One) 307 return 1; 308 if (type >= ValueHandleType.Int8 && type <= ValueHandleType.Int64) 309 { 310 long value = ToLong(); 311 if (value >= 0) 312 return (ulong)value; 313 } 314 if (type == ValueHandleType.UInt64) 315 return GetUInt64(); 316 if (type == ValueHandleType.UTF8) 317 return XmlConverter.ToUInt64(_bufferReader.Buffer, _offset, _length); 318 return XmlConverter.ToUInt64(GetString()); 319 } 320 ToSingle()321 public Single ToSingle() 322 { 323 ValueHandleType type = _type; 324 if (type == ValueHandleType.Single) 325 return GetSingle(); 326 if (type == ValueHandleType.Double) 327 { 328 double value = GetDouble(); 329 330 if ((value >= Single.MinValue && value <= Single.MaxValue) || !double.IsFinite(value)) 331 { 332 return (Single)value; 333 } 334 } 335 if (type == ValueHandleType.Zero) 336 return 0; 337 if (type == ValueHandleType.One) 338 return 1; 339 if (type == ValueHandleType.Int8) 340 return GetInt8(); 341 if (type == ValueHandleType.Int16) 342 return GetInt16(); 343 if (type == ValueHandleType.UTF8) 344 return XmlConverter.ToSingle(_bufferReader.Buffer, _offset, _length); 345 return XmlConverter.ToSingle(GetString()); 346 } 347 ToDouble()348 public Double ToDouble() 349 { 350 ValueHandleType type = _type; 351 if (type == ValueHandleType.Double) 352 return GetDouble(); 353 if (type == ValueHandleType.Single) 354 return GetSingle(); 355 if (type == ValueHandleType.Zero) 356 return 0; 357 if (type == ValueHandleType.One) 358 return 1; 359 if (type == ValueHandleType.Int8) 360 return GetInt8(); 361 if (type == ValueHandleType.Int16) 362 return GetInt16(); 363 if (type == ValueHandleType.Int32) 364 return GetInt32(); 365 if (type == ValueHandleType.UTF8) 366 return XmlConverter.ToDouble(_bufferReader.Buffer, _offset, _length); 367 return XmlConverter.ToDouble(GetString()); 368 } 369 ToDecimal()370 public Decimal ToDecimal() 371 { 372 ValueHandleType type = _type; 373 if (type == ValueHandleType.Decimal) 374 return GetDecimal(); 375 if (type == ValueHandleType.Zero) 376 return 0; 377 if (type == ValueHandleType.One) 378 return 1; 379 if (type >= ValueHandleType.Int8 && type <= ValueHandleType.Int64) 380 return ToLong(); 381 if (type == ValueHandleType.UInt64) 382 return GetUInt64(); 383 if (type == ValueHandleType.UTF8) 384 return XmlConverter.ToDecimal(_bufferReader.Buffer, _offset, _length); 385 return XmlConverter.ToDecimal(GetString()); 386 } 387 ToDateTime()388 public DateTime ToDateTime() 389 { 390 if (_type == ValueHandleType.DateTime) 391 { 392 return XmlConverter.ToDateTime(GetInt64()); 393 } 394 if (_type == ValueHandleType.UTF8) 395 { 396 return XmlConverter.ToDateTime(_bufferReader.Buffer, _offset, _length); 397 } 398 return XmlConverter.ToDateTime(GetString()); 399 } 400 ToUniqueId()401 public UniqueId ToUniqueId() 402 { 403 if (_type == ValueHandleType.UniqueId) 404 return GetUniqueId(); 405 if (_type == ValueHandleType.UTF8) 406 return XmlConverter.ToUniqueId(_bufferReader.Buffer, _offset, _length); 407 return XmlConverter.ToUniqueId(GetString()); 408 } 409 ToTimeSpan()410 public TimeSpan ToTimeSpan() 411 { 412 if (_type == ValueHandleType.TimeSpan) 413 return new TimeSpan(GetInt64()); 414 if (_type == ValueHandleType.UTF8) 415 return XmlConverter.ToTimeSpan(_bufferReader.Buffer, _offset, _length); 416 return XmlConverter.ToTimeSpan(GetString()); 417 } 418 ToGuid()419 public Guid ToGuid() 420 { 421 if (_type == ValueHandleType.Guid) 422 return GetGuid(); 423 if (_type == ValueHandleType.UTF8) 424 return XmlConverter.ToGuid(_bufferReader.Buffer, _offset, _length); 425 return XmlConverter.ToGuid(GetString()); 426 } ToString()427 public override string ToString() 428 { 429 return GetString(); 430 } 431 ToByteArray()432 public byte[] ToByteArray() 433 { 434 if (_type == ValueHandleType.Base64) 435 { 436 byte[] buffer = new byte[_length]; 437 GetBase64(buffer, 0, _length); 438 return buffer; 439 } 440 if (_type == ValueHandleType.UTF8 && (_length % 4) == 0) 441 { 442 try 443 { 444 int expectedLength = _length / 4 * 3; 445 if (_length > 0) 446 { 447 if (_bufferReader.Buffer[_offset + _length - 1] == '=') 448 { 449 expectedLength--; 450 if (_bufferReader.Buffer[_offset + _length - 2] == '=') 451 expectedLength--; 452 } 453 } 454 byte[] buffer = new byte[expectedLength]; 455 int actualLength = Base64Encoding.GetBytes(_bufferReader.Buffer, _offset, _length, buffer, 0); 456 if (actualLength != buffer.Length) 457 { 458 byte[] newBuffer = new byte[actualLength]; 459 Buffer.BlockCopy(buffer, 0, newBuffer, 0, actualLength); 460 buffer = newBuffer; 461 } 462 return buffer; 463 } 464 catch (FormatException) 465 { 466 // Something unhappy with the characters, fall back to the hard way 467 } 468 } 469 try 470 { 471 return Base64Encoding.GetBytes(XmlConverter.StripWhitespace(GetString())); 472 } 473 catch (FormatException exception) 474 { 475 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(exception.Message, exception.InnerException)); 476 } 477 } 478 GetString()479 public string GetString() 480 { 481 ValueHandleType type = _type; 482 if (type == ValueHandleType.UTF8) 483 return GetCharsText(); 484 485 switch (type) 486 { 487 case ValueHandleType.False: 488 return "false"; 489 case ValueHandleType.True: 490 return "true"; 491 case ValueHandleType.Zero: 492 return "0"; 493 case ValueHandleType.One: 494 return "1"; 495 case ValueHandleType.Int8: 496 case ValueHandleType.Int16: 497 case ValueHandleType.Int32: 498 return XmlConverter.ToString(ToInt()); 499 case ValueHandleType.Int64: 500 return XmlConverter.ToString(GetInt64()); 501 case ValueHandleType.UInt64: 502 return XmlConverter.ToString(GetUInt64()); 503 case ValueHandleType.Single: 504 return XmlConverter.ToString(GetSingle()); 505 case ValueHandleType.Double: 506 return XmlConverter.ToString(GetDouble()); 507 case ValueHandleType.Decimal: 508 return XmlConverter.ToString(GetDecimal()); 509 case ValueHandleType.DateTime: 510 return XmlConverter.ToString(ToDateTime()); 511 case ValueHandleType.Empty: 512 return string.Empty; 513 case ValueHandleType.Unicode: 514 return GetUnicodeCharsText(); 515 case ValueHandleType.EscapedUTF8: 516 return GetEscapedCharsText(); 517 case ValueHandleType.Char: 518 return GetCharText(); 519 case ValueHandleType.Dictionary: 520 return GetDictionaryString().Value; 521 case ValueHandleType.Base64: 522 byte[] bytes = ToByteArray(); 523 DiagnosticUtility.DebugAssert(bytes != null, ""); 524 return Base64Encoding.GetString(bytes, 0, bytes.Length); 525 case ValueHandleType.List: 526 return XmlConverter.ToString(ToList()); 527 case ValueHandleType.UniqueId: 528 return XmlConverter.ToString(ToUniqueId()); 529 case ValueHandleType.Guid: 530 return XmlConverter.ToString(ToGuid()); 531 case ValueHandleType.TimeSpan: 532 return XmlConverter.ToString(ToTimeSpan()); 533 case ValueHandleType.QName: 534 return GetQNameDictionaryText(); 535 case ValueHandleType.ConstString: 536 return s_constStrings[_offset]; 537 default: 538 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException()); 539 } 540 } 541 542 // ASSUMPTION (Microsoft): all chars in str will be ASCII Equals2(string str, bool checkLower)543 public bool Equals2(string str, bool checkLower) 544 { 545 if (_type != ValueHandleType.UTF8) 546 return GetString() == str; 547 548 if (_length != str.Length) 549 return false; 550 551 byte[] buffer = _bufferReader.Buffer; 552 for (int i = 0; i < _length; ++i) 553 { 554 DiagnosticUtility.DebugAssert(str[i] < 128, ""); 555 byte ch = buffer[i + _offset]; 556 if (ch == str[i]) 557 continue; 558 559 if (checkLower && char.ToLowerInvariant((char)ch) == str[i]) 560 continue; 561 562 return false; 563 } 564 565 return true; 566 } 567 Sign(XmlSigningNodeWriter writer)568 public void Sign(XmlSigningNodeWriter writer) 569 { 570 switch (_type) 571 { 572 case ValueHandleType.Int8: 573 case ValueHandleType.Int16: 574 case ValueHandleType.Int32: 575 writer.WriteInt32Text(ToInt()); 576 break; 577 case ValueHandleType.Int64: 578 writer.WriteInt64Text(GetInt64()); 579 break; 580 case ValueHandleType.UInt64: 581 writer.WriteUInt64Text(GetUInt64()); 582 break; 583 case ValueHandleType.Single: 584 writer.WriteFloatText(GetSingle()); 585 break; 586 case ValueHandleType.Double: 587 writer.WriteDoubleText(GetDouble()); 588 break; 589 case ValueHandleType.Decimal: 590 writer.WriteDecimalText(GetDecimal()); 591 break; 592 case ValueHandleType.DateTime: 593 writer.WriteDateTimeText(ToDateTime()); 594 break; 595 case ValueHandleType.Empty: 596 break; 597 case ValueHandleType.UTF8: 598 writer.WriteEscapedText(_bufferReader.Buffer, _offset, _length); 599 break; 600 case ValueHandleType.Base64: 601 writer.WriteBase64Text(_bufferReader.Buffer, 0, _bufferReader.Buffer, _offset, _length); 602 break; 603 case ValueHandleType.UniqueId: 604 writer.WriteUniqueIdText(ToUniqueId()); 605 break; 606 case ValueHandleType.Guid: 607 writer.WriteGuidText(ToGuid()); 608 break; 609 case ValueHandleType.TimeSpan: 610 writer.WriteTimeSpanText(ToTimeSpan()); 611 break; 612 default: 613 writer.WriteEscapedText(GetString()); 614 break; 615 } 616 } 617 ToList()618 public object[] ToList() 619 { 620 return _bufferReader.GetList(_offset, _length); 621 } 622 ToObject()623 public object ToObject() 624 { 625 switch (_type) 626 { 627 case ValueHandleType.False: 628 case ValueHandleType.True: 629 return ToBoolean(); 630 case ValueHandleType.Zero: 631 case ValueHandleType.One: 632 case ValueHandleType.Int8: 633 case ValueHandleType.Int16: 634 case ValueHandleType.Int32: 635 return ToInt(); 636 case ValueHandleType.Int64: 637 return ToLong(); 638 case ValueHandleType.UInt64: 639 return GetUInt64(); 640 case ValueHandleType.Single: 641 return ToSingle(); 642 case ValueHandleType.Double: 643 return ToDouble(); 644 case ValueHandleType.Decimal: 645 return ToDecimal(); 646 case ValueHandleType.DateTime: 647 return ToDateTime(); 648 case ValueHandleType.Empty: 649 case ValueHandleType.UTF8: 650 case ValueHandleType.Unicode: 651 case ValueHandleType.EscapedUTF8: 652 case ValueHandleType.Dictionary: 653 case ValueHandleType.Char: 654 case ValueHandleType.ConstString: 655 return ToString(); 656 case ValueHandleType.Base64: 657 return ToByteArray(); 658 case ValueHandleType.List: 659 return ToList(); 660 case ValueHandleType.UniqueId: 661 return ToUniqueId(); 662 case ValueHandleType.Guid: 663 return ToGuid(); 664 case ValueHandleType.TimeSpan: 665 return ToTimeSpan(); 666 default: 667 throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException()); 668 } 669 } 670 TryReadBase64(byte[] buffer, int offset, int count, out int actual)671 public bool TryReadBase64(byte[] buffer, int offset, int count, out int actual) 672 { 673 if (_type == ValueHandleType.Base64) 674 { 675 actual = Math.Min(_length, count); 676 GetBase64(buffer, offset, actual); 677 _offset += actual; 678 _length -= actual; 679 return true; 680 } 681 if (_type == ValueHandleType.UTF8 && count >= 3 && (_length % 4) == 0) 682 { 683 try 684 { 685 int charCount = Math.Min(count / 3 * 4, _length); 686 actual = Base64Encoding.GetBytes(_bufferReader.Buffer, _offset, charCount, buffer, offset); 687 _offset += charCount; 688 _length -= charCount; 689 return true; 690 } 691 catch (FormatException) 692 { 693 // Something unhappy with the characters, fall back to the hard way 694 } 695 } 696 actual = 0; 697 return false; 698 } 699 TryReadChars(char[] chars, int offset, int count, out int actual)700 public bool TryReadChars(char[] chars, int offset, int count, out int actual) 701 { 702 DiagnosticUtility.DebugAssert(offset + count <= chars.Length, string.Format("offset '{0}' + count '{1}' MUST BE <= chars.Length '{2}'", offset, count, chars.Length)); 703 704 if (_type == ValueHandleType.Unicode) 705 return TryReadUnicodeChars(chars, offset, count, out actual); 706 707 if (_type != ValueHandleType.UTF8) 708 { 709 actual = 0; 710 return false; 711 } 712 713 int charOffset = offset; 714 int charCount = count; 715 byte[] bytes = _bufferReader.Buffer; 716 int byteOffset = _offset; 717 int byteCount = _length; 718 bool insufficientSpaceInCharsArray = false; 719 720 var encoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true); 721 while (true) 722 { 723 while (charCount > 0 && byteCount > 0) 724 { 725 // fast path for codepoints U+0000 - U+007F 726 byte b = bytes[byteOffset]; 727 if (b >= 0x80) 728 break; 729 chars[charOffset] = (char)b; 730 byteOffset++; 731 byteCount--; 732 charOffset++; 733 charCount--; 734 } 735 736 if (charCount == 0 || byteCount == 0 || insufficientSpaceInCharsArray) 737 break; 738 739 int actualByteCount; 740 int actualCharCount; 741 742 try 743 { 744 // If we're asking for more than are possibly available, or more than are truly available then we can return the entire thing 745 if (charCount >= encoding.GetMaxCharCount(byteCount) || charCount >= encoding.GetCharCount(bytes, byteOffset, byteCount)) 746 { 747 actualCharCount = encoding.GetChars(bytes, byteOffset, byteCount, chars, charOffset); 748 actualByteCount = byteCount; 749 } 750 else 751 { 752 Decoder decoder = encoding.GetDecoder(); 753 754 // Since x bytes can never generate more than x characters this is a safe estimate as to what will fit 755 actualByteCount = Math.Min(charCount, byteCount); 756 757 // We use a decoder so we don't error if we fall across a character boundary 758 actualCharCount = decoder.GetChars(bytes, byteOffset, actualByteCount, chars, charOffset); 759 760 // We might have gotten zero characters though if < 4 bytes were requested because 761 // codepoints from U+0000 - U+FFFF can be up to 3 bytes in UTF-8, and represented as ONE char 762 // codepoints from U+10000 - U+10FFFF (last Unicode codepoint representable in UTF-8) are represented by up to 4 bytes in UTF-8 763 // and represented as TWO chars (high+low surrogate) 764 // (e.g. 1 char requested, 1 char in the buffer represented in 3 bytes) 765 while (actualCharCount == 0) 766 { 767 // Note the by the time we arrive here, if actualByteCount == 3, the next decoder.GetChars() call will read the 4th byte 768 // if we don't bail out since the while loop will advance actualByteCount only after reading the byte. 769 if (actualByteCount >= 3 && charCount < 2) 770 { 771 // If we reach here, it means that we're: 772 // - trying to decode more than 3 bytes and, 773 // - there is only one char left of charCount where we're stuffing decoded characters. 774 // In this case, we need to back off since decoding > 3 bytes in UTF-8 means that we will get 2 16-bit chars 775 // (a high surrogate and a low surrogate) - the Decoder will attempt to provide both at once 776 // and an ArgumentException will be thrown complaining that there's not enough space in the output char array. 777 778 // actualByteCount = 0 when the while loop is broken out of; decoder goes out of scope so its state no longer matters 779 780 insufficientSpaceInCharsArray = true; 781 break; 782 } 783 else 784 { 785 DiagnosticUtility.DebugAssert(byteOffset + actualByteCount < bytes.Length, 786 string.Format("byteOffset {0} + actualByteCount {1} MUST BE < bytes.Length {2}", byteOffset, actualByteCount, bytes.Length)); 787 788 // Request a few more bytes to get at least one character 789 actualCharCount = decoder.GetChars(bytes, byteOffset + actualByteCount, 1, chars, charOffset); 790 actualByteCount++; 791 } 792 } 793 794 // Now that we actually retrieved some characters, figure out how many bytes it actually was 795 actualByteCount = encoding.GetByteCount(chars, charOffset, actualCharCount); 796 } 797 } 798 catch (FormatException exception) 799 { 800 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(XmlExceptionHelper.CreateEncodingException(bytes, byteOffset, byteCount, exception)); 801 } 802 803 // Advance 804 byteOffset += actualByteCount; 805 byteCount -= actualByteCount; 806 807 charOffset += actualCharCount; 808 charCount -= actualCharCount; 809 } 810 811 _offset = byteOffset; 812 _length = byteCount; 813 814 actual = (count - charCount); 815 return true; 816 } 817 TryReadUnicodeChars(char[] chars, int offset, int count, out int actual)818 private bool TryReadUnicodeChars(char[] chars, int offset, int count, out int actual) 819 { 820 int charCount = Math.Min(count, _length / sizeof(char)); 821 for (int i = 0; i < charCount; i++) 822 { 823 chars[offset + i] = (char)_bufferReader.GetInt16(_offset + i * sizeof(char)); 824 } 825 _offset += charCount * sizeof(char); 826 _length -= charCount * sizeof(char); 827 actual = charCount; 828 return true; 829 } 830 TryGetDictionaryString(out XmlDictionaryString value)831 public bool TryGetDictionaryString(out XmlDictionaryString value) 832 { 833 if (_type == ValueHandleType.Dictionary) 834 { 835 value = GetDictionaryString(); 836 return true; 837 } 838 else 839 { 840 value = null; 841 return false; 842 } 843 } 844 TryGetByteArrayLength(out int length)845 public bool TryGetByteArrayLength(out int length) 846 { 847 if (_type == ValueHandleType.Base64) 848 { 849 length = _length; 850 return true; 851 } 852 length = 0; 853 return false; 854 } GetCharsText()855 private string GetCharsText() 856 { 857 DiagnosticUtility.DebugAssert(_type == ValueHandleType.UTF8, ""); 858 if (_length == 1 && _bufferReader.GetByte(_offset) == '1') 859 return "1"; 860 return _bufferReader.GetString(_offset, _length); 861 } 862 GetUnicodeCharsText()863 private string GetUnicodeCharsText() 864 { 865 DiagnosticUtility.DebugAssert(_type == ValueHandleType.Unicode, ""); 866 return _bufferReader.GetUnicodeString(_offset, _length); 867 } 868 GetEscapedCharsText()869 private string GetEscapedCharsText() 870 { 871 DiagnosticUtility.DebugAssert(_type == ValueHandleType.EscapedUTF8, ""); 872 return _bufferReader.GetEscapedString(_offset, _length); 873 } GetCharText()874 private string GetCharText() 875 { 876 int ch = GetChar(); 877 if (ch > char.MaxValue) 878 { 879 SurrogateChar surrogate = new SurrogateChar(ch); 880 char[] chars = new char[2]; 881 chars[0] = surrogate.HighChar; 882 chars[1] = surrogate.LowChar; 883 return new string(chars, 0, 2); 884 } 885 else 886 { 887 return ((char)ch).ToString(); 888 } 889 } 890 GetChar()891 private int GetChar() 892 { 893 DiagnosticUtility.DebugAssert(_type == ValueHandleType.Char, ""); 894 return _offset; 895 } 896 GetInt8()897 private int GetInt8() 898 { 899 DiagnosticUtility.DebugAssert(_type == ValueHandleType.Int8, ""); 900 return _bufferReader.GetInt8(_offset); 901 } 902 GetInt16()903 private int GetInt16() 904 { 905 DiagnosticUtility.DebugAssert(_type == ValueHandleType.Int16, ""); 906 return _bufferReader.GetInt16(_offset); 907 } 908 GetInt32()909 private int GetInt32() 910 { 911 DiagnosticUtility.DebugAssert(_type == ValueHandleType.Int32, ""); 912 return _bufferReader.GetInt32(_offset); 913 } 914 GetInt64()915 private long GetInt64() 916 { 917 DiagnosticUtility.DebugAssert(_type == ValueHandleType.Int64 || _type == ValueHandleType.TimeSpan || _type == ValueHandleType.DateTime, ""); 918 return _bufferReader.GetInt64(_offset); 919 } 920 GetUInt64()921 private ulong GetUInt64() 922 { 923 DiagnosticUtility.DebugAssert(_type == ValueHandleType.UInt64, ""); 924 return _bufferReader.GetUInt64(_offset); 925 } 926 GetSingle()927 private float GetSingle() 928 { 929 DiagnosticUtility.DebugAssert(_type == ValueHandleType.Single, ""); 930 return _bufferReader.GetSingle(_offset); 931 } 932 GetDouble()933 private double GetDouble() 934 { 935 DiagnosticUtility.DebugAssert(_type == ValueHandleType.Double, ""); 936 return _bufferReader.GetDouble(_offset); 937 } 938 GetDecimal()939 private decimal GetDecimal() 940 { 941 DiagnosticUtility.DebugAssert(_type == ValueHandleType.Decimal, ""); 942 return _bufferReader.GetDecimal(_offset); 943 } 944 GetUniqueId()945 private UniqueId GetUniqueId() 946 { 947 DiagnosticUtility.DebugAssert(_type == ValueHandleType.UniqueId, ""); 948 return _bufferReader.GetUniqueId(_offset); 949 } 950 GetGuid()951 private Guid GetGuid() 952 { 953 DiagnosticUtility.DebugAssert(_type == ValueHandleType.Guid, ""); 954 return _bufferReader.GetGuid(_offset); 955 } 956 GetBase64(byte[] buffer, int offset, int count)957 private void GetBase64(byte[] buffer, int offset, int count) 958 { 959 DiagnosticUtility.DebugAssert(_type == ValueHandleType.Base64, ""); 960 _bufferReader.GetBase64(_offset, buffer, offset, count); 961 } 962 GetDictionaryString()963 private XmlDictionaryString GetDictionaryString() 964 { 965 DiagnosticUtility.DebugAssert(_type == ValueHandleType.Dictionary, ""); 966 return _bufferReader.GetDictionaryString(_offset); 967 } 968 GetQNameDictionaryText()969 private string GetQNameDictionaryText() 970 { 971 DiagnosticUtility.DebugAssert(_type == ValueHandleType.QName, ""); 972 return string.Concat(PrefixHandle.GetString(PrefixHandle.GetAlphaPrefix(_length)), ":", _bufferReader.GetDictionaryString(_offset)); 973 } 974 } 975 } 976