2 * UTF8Encoding.cs - Implementation of the "System.Text.UTF8Encoding" class.
4 * Copyright (c) 2001, 2002 Southern Storm Software, Pty Ltd
5 * Copyright (C) 2004 Novell, Inc (http://www.novell.com)
7 * Permission is hereby granted, free of charge, to any person obtaining
8 * a copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 * OTHER DEALINGS IN THE SOFTWARE.
32 [MonoTODO ("Fix serialization compatibility with MS.NET")]
34 [MonoTODO ("EncoderFallback is not handled")]
36 public class UTF8Encoding : Encoding
38 // Magic number used by Windows for UTF-8.
39 internal const int UTF8_CODE_PAGE = 65001;
42 private bool emitIdentifier;
44 private bool throwOnInvalid;
48 public UTF8Encoding () : this (false, false) {}
49 public UTF8Encoding (bool encoderShouldEmitUTF8Identifier)
50 : this (encoderShouldEmitUTF8Identifier, false) {}
52 public UTF8Encoding (bool encoderShouldEmitUTF8Identifier, bool throwOnInvalidBytes)
53 : base (UTF8_CODE_PAGE)
55 emitIdentifier = encoderShouldEmitUTF8Identifier;
57 if (throwOnInvalidBytes)
58 SetFallbackInternal (null, new DecoderExceptionFallback ());
60 SetFallbackInternal (null, new DecoderReplacementFallback (String.Empty));
62 throwOnInvalid = throwOnInvalidBytes;
65 web_name = body_name = header_name = "utf-8";
66 encoding_name = "Unicode (UTF-8)";
67 is_browser_save = true;
68 is_browser_display = true;
69 is_mail_news_display = true;
70 windows_code_page = UnicodeEncoding.UNICODE_CODE_PAGE;
73 #region GetByteCount()
75 // Internal version of "GetByteCount" which can handle a rolling
76 // state between multiple calls to this method.
77 private static int InternalGetByteCount (char[] chars, int index, int count, ref uint leftOver, bool flush)
79 // Validate the parameters.
81 throw new ArgumentNullException ("chars");
83 if (index < 0 || index > chars.Length) {
84 throw new ArgumentOutOfRangeException ("index", _("ArgRange_Array"));
86 if (count < 0 || count > (chars.Length - index)) {
87 throw new ArgumentOutOfRangeException ("count", _("ArgRange_Array"));
90 if (index == chars.Length) {
91 if (flush && leftOver != 0) {
92 // Flush the left-over surrogate pair start.
100 fixed (char* cptr = chars) {
101 return InternalGetByteCount (cptr + index, count, ref leftOver, flush);
107 private unsafe static int InternalGetByteCount (char* chars, int count, ref uint leftOver, bool flush)
111 // Determine the lengths of all characters.
114 uint pair = leftOver;
120 } else if (ch < '\u0800') {
122 } else if (ch >= '\uD800' && ch <= '\uDBFF') {
123 // This is the start of a surrogate pair.
128 } else if (ch >= '\uDC00' && ch <= '\uDFFF') {
129 // We have a surrogate pair.
133 // We have a surrogate start followed by a
134 // regular character. Technically, this is
135 // invalid, but we have to do something.
136 // We write out the surrogate start and then
137 // re-visit the current character again.
145 if (flush && pair != 0) {
146 // Flush the left-over surrogate pair start.
152 // Return the final length to the caller.
156 // Get the number of bytes needed to encode a character buffer.
157 public override int GetByteCount (char[] chars, int index, int count)
160 return InternalGetByteCount (chars, index, count, ref dummy, true);
163 // Convenience wrappers for "GetByteCount".
164 public override int GetByteCount (String s)
166 // Validate the parameters.
168 throw new ArgumentNullException ("s");
172 fixed (char* cptr = s) {
174 return InternalGetByteCount (cptr, s.Length, ref dummy, true);
183 // Internal version of "GetBytes" which can handle a rolling
184 // state between multiple calls to this method.
185 private static int InternalGetBytes (char[] chars, int charIndex,
186 int charCount, byte[] bytes,
187 int byteIndex, ref uint leftOver,
190 // Validate the parameters.
192 throw new ArgumentNullException ("chars");
195 throw new ArgumentNullException ("bytes");
197 if (charIndex < 0 || charIndex > chars.Length) {
198 throw new ArgumentOutOfRangeException ("charIndex", _("ArgRange_Array"));
200 if (charCount < 0 || charCount > (chars.Length - charIndex)) {
201 throw new ArgumentOutOfRangeException ("charCount", _("ArgRange_Array"));
203 if (byteIndex < 0 || byteIndex > bytes.Length) {
204 throw new ArgumentOutOfRangeException ("byteIndex", _("ArgRange_Array"));
207 if (charIndex == chars.Length) {
208 if (flush && leftOver != 0) {
209 // Flush the left-over surrogate pair start.
210 bytes [byteIndex++] = 0xEF;
211 bytes [byteIndex++] = 0xBB;
212 bytes [byteIndex++] = 0xBF;
220 fixed (char* cptr = chars) {
221 fixed (byte *bptr = bytes) {
222 return InternalGetBytes (
223 cptr + charIndex, charCount,
224 bptr + byteIndex, bytes.Length - byteIndex,
225 ref leftOver, flush);
231 private unsafe static int InternalGetBytes (char* chars, int charCount,
232 byte* bytes, int byteCount,
233 ref uint leftOver, bool flush)
238 // Convert the characters into bytes.
239 // Convert the characters into bytes.
241 int length = byteCount;
242 uint pair = leftOver;
243 int posn = byteIndex;
245 while (charCount > 0) {
246 // Fetch the next UTF-16 character pair value.
247 ch = chars [charIndex++];
248 if (ch >= '\uD800' && ch <= '\uDBFF' && charCount > 1) {
249 // This may be the start of a surrogate pair.
250 pair = (uint) chars [charIndex];
251 if (pair >= 0xDC00 && pair <= 0xDFFF) {
252 pair = pair - 0xDC00 +
253 (((uint) ch - 0xD800) << 10) +
265 // Encode the character pair value.
268 throw new ArgumentException (_("Arg_InsufficientSpace"), "bytes");
269 bytes [posn++] = (byte)pair;
270 } else if (pair < 0x0800) {
271 if ((posn + 2) > length)
272 throw new ArgumentException (_("Arg_InsufficientSpace"), "bytes");
273 bytes [posn++] = (byte) (0xC0 | (pair >> 6));
274 bytes [posn++] = (byte) (0x80 | (pair & 0x3F));
275 } else if (pair < 0x10000) {
276 if ((posn + 3) > length)
277 throw new ArgumentException (_("Arg_InsufficientSpace"), "bytes");
278 bytes [posn++] = (byte) (0xE0 | (pair >> 12));
279 bytes [posn++] = (byte) (0x80 | ((pair >> 6) & 0x3F));
280 bytes [posn++] = (byte) (0x80 | (pair & 0x3F));
282 if ((posn + 4) > length)
283 throw new ArgumentException (_("Arg_InsufficientSpace"), "bytes");
284 bytes [posn++] = (byte) (0xF0 | (pair >> 18));
285 bytes [posn++] = (byte) (0x80 | ((pair >> 12) & 0x3F));
286 bytes [posn++] = (byte) (0x80 | ((pair >> 6) & 0x3F));
287 bytes [posn++] = (byte) (0x80 | (pair & 0x3F));
291 if (flush && pair >= 0xD800 && pair < 0xDC00) {
292 // Flush the left-over surrogate pair start.
293 if ((posn + 3) > length) {
294 throw new ArgumentException (_("Arg_InsufficientSpace"), "bytes");
296 bytes [posn++] = (byte) (0xE0 | (pair >> 12));
297 bytes [posn++] = (byte) (0x80 | ((pair >> 6) & 0x3F));
298 bytes [posn++] = (byte) (0x80 | (pair & 0x3F));
304 // Return the final count to the caller.
305 return posn - byteIndex;
308 // Get the bytes that result from encoding a character buffer.
309 public override int GetBytes (char[] chars, int charIndex, int charCount,
310 byte[] bytes, int byteIndex)
313 return InternalGetBytes (chars, charIndex, charCount, bytes, byteIndex, ref leftOver, true);
316 // Convenience wrappers for "GetBytes".
317 public override int GetBytes (String s, int charIndex, int charCount,
318 byte[] bytes, int byteIndex)
320 // Validate the parameters.
322 throw new ArgumentNullException ("s");
325 throw new ArgumentNullException ("bytes");
327 if (charIndex < 0 || charIndex > s.Length) {
328 throw new ArgumentOutOfRangeException ("charIndex", _("ArgRange_StringIndex"));
330 if (charCount < 0 || charCount > (s.Length - charIndex)) {
331 throw new ArgumentOutOfRangeException ("charCount", _("ArgRange_StringRange"));
333 if (byteIndex < 0 || byteIndex > bytes.Length) {
334 throw new ArgumentOutOfRangeException ("byteIndex", _("ArgRange_Array"));
337 if (charIndex == s.Length)
341 fixed (char* cptr = s) {
342 fixed (byte *bptr = bytes) {
344 return InternalGetBytes (
345 cptr + charIndex, charCount,
346 bptr + byteIndex, bytes.Length - byteIndex,
355 // Internal version of "GetCharCount" which can handle a rolling
356 // state between multiple calls to this method.
358 // Internal version of "GetCharCount" which can handle a rolling
359 // state between multiple calls to this method.
360 private static int InternalGetCharCount (
361 byte[] bytes, int index, int count, uint leftOverBits,
362 uint leftOverCount, object provider,
363 ref DecoderFallbackBuffer fallbackBuffer, bool flush)
365 private static int InternalGetCharCount (
366 byte[] bytes, int index, int count, uint leftOverBits,
367 uint leftOverCount, bool throwOnInvalid, bool flush)
370 // Validate the parameters.
372 throw new ArgumentNullException ("bytes");
374 if (index < 0 || index > bytes.Length) {
375 throw new ArgumentOutOfRangeException ("index", _("ArgRange_Array"));
377 if (count < 0 || count > (bytes.Length - index)) {
378 throw new ArgumentOutOfRangeException ("count", _("ArgRange_Array"));
383 if (leftOverCount == 0) {
384 int end = index + count;
385 for (; index < end; index++, count--) {
386 if (bytes [index] < 0x80)
393 // Determine the number of characters that we have.
395 uint leftBits = leftOverBits;
396 uint leftSoFar = (leftOverCount & (uint)0x0F);
397 uint leftSize = ((leftOverCount >> 4) & (uint)0x0F);
399 ch = (uint)(bytes[index++]);
402 // Process a UTF-8 start character.
403 if (ch < (uint)0x0080) {
404 // Single-byte UTF-8 character.
406 } else if ((ch & (uint)0xE0) == (uint)0xC0) {
407 // Double-byte UTF-8 character.
408 leftBits = (ch & (uint)0x1F);
411 } else if ((ch & (uint)0xF0) == (uint)0xE0) {
412 // Three-byte UTF-8 character.
413 leftBits = (ch & (uint)0x0F);
416 } else if ((ch & (uint)0xF8) == (uint)0xF0) {
417 // Four-byte UTF-8 character.
418 leftBits = (ch & (uint)0x07);
421 } else if ((ch & (uint)0xFC) == (uint)0xF8) {
422 // Five-byte UTF-8 character.
423 leftBits = (ch & (uint)0x03);
426 } else if ((ch & (uint)0xFE) == (uint)0xFC) {
427 // Six-byte UTF-8 character.
428 leftBits = (ch & (uint)0x03);
432 // Invalid UTF-8 start character.
434 length += Fallback (provider, ref fallbackBuffer, bytes, index - 1);
437 throw new ArgumentException (_("Arg_InvalidUTF8"), "bytes");
441 // Process an extra byte in a multi-byte sequence.
442 if ((ch & (uint)0xC0) == (uint)0x80) {
443 leftBits = ((leftBits << 6) | (ch & (uint)0x3F));
444 if (++leftSoFar >= leftSize) {
445 // We have a complete character now.
446 if (leftBits < (uint)0x10000) {
447 // is it an overlong ?
448 bool overlong = false;
451 overlong = (leftBits <= 0x7F);
454 overlong = (leftBits <= 0x07FF);
457 overlong = (leftBits <= 0xFFFF);
460 overlong = (leftBits <= 0x1FFFFF);
463 overlong = (leftBits <= 0x03FFFFFF);
468 length += Fallback (provider, ref fallbackBuffer, bytes, index - 1);
471 throw new ArgumentException (_("Overlong"), leftBits.ToString ());
476 } else if (leftBits < (uint)0x110000) {
480 length += Fallback (provider, ref fallbackBuffer, bytes, index - 1);
483 throw new ArgumentException (_("Arg_InvalidUTF8"), "bytes");
489 // Invalid UTF-8 sequence: clear and restart.
491 length += Fallback (provider, ref fallbackBuffer, bytes, index - 1);
494 throw new ArgumentException (_("Arg_InvalidUTF8"), "bytes");
502 if (flush && leftSize != 0) {
503 // We had left-over bytes that didn't make up
504 // a complete UTF-8 character sequence.
506 length += Fallback (provider, ref fallbackBuffer, bytes, index - 1);
509 throw new ArgumentException (_("Arg_InvalidUTF8"), "bytes");
513 // Return the final length to the caller.
518 // for GetCharCount()
519 static int Fallback (object provider, ref DecoderFallbackBuffer buffer, byte [] bytes, int index)
521 if (buffer == null) {
522 DecoderFallback fb = provider as DecoderFallback;
524 buffer = fb.CreateFallbackBuffer ();
526 buffer = ((Decoder) provider).FallbackBuffer;
528 buffer.Fallback (bytes, index - 1);
529 return buffer.Remaining;
533 static void Fallback (object provider, ref DecoderFallbackBuffer buffer, byte [] bytes, int byteIndex,
534 char [] chars, ref int charIndex)
536 if (buffer == null) {
537 DecoderFallback fb = provider as DecoderFallback;
539 buffer = fb.CreateFallbackBuffer ();
541 buffer = ((Decoder) provider).FallbackBuffer;
543 buffer.Fallback (bytes, byteIndex - 1);
544 while (buffer.Remaining > 0)
545 chars [charIndex++] = buffer.GetNextChar ();
549 // Get the number of characters needed to decode a byte buffer.
550 public override int GetCharCount (byte[] bytes, int index, int count)
553 DecoderFallbackBuffer buf = null;
554 return InternalGetCharCount (bytes, index, count, 0, 0, DecoderFallback, ref buf, true);
556 return InternalGetCharCount (bytes, index, count, 0, 0, throwOnInvalid, true);
560 // Get the characters that result from decoding a byte buffer.
562 private static int InternalGetChars (
563 byte[] bytes, int byteIndex, int byteCount, char[] chars,
564 int charIndex, ref uint leftOverBits, ref uint leftOverCount,
566 ref DecoderFallbackBuffer fallbackBuffer, bool flush)
568 private static int InternalGetChars (
569 byte[] bytes, int byteIndex, int byteCount, char[] chars,
570 int charIndex, ref uint leftOverBits, ref uint leftOverCount,
571 bool throwOnInvalid, bool flush)
574 // Validate the parameters.
576 throw new ArgumentNullException ("bytes");
579 throw new ArgumentNullException ("chars");
581 if (byteIndex < 0 || byteIndex > bytes.Length) {
582 throw new ArgumentOutOfRangeException ("byteIndex", _("ArgRange_Array"));
584 if (byteCount < 0 || byteCount > (bytes.Length - byteIndex)) {
585 throw new ArgumentOutOfRangeException ("byteCount", _("ArgRange_Array"));
587 if (charIndex < 0 || charIndex > chars.Length) {
588 throw new ArgumentOutOfRangeException ("charIndex", _("ArgRange_Array"));
591 if (charIndex == chars.Length)
594 int posn = charIndex;
596 if (leftOverCount == 0) {
597 int end = byteIndex + byteCount;
598 for (; byteIndex < end; posn++, byteIndex++, byteCount--) {
599 if (bytes [byteIndex] < 0x80)
600 chars [posn] = (char) bytes [byteIndex];
606 // Convert the bytes into the output buffer.
608 int length = chars.Length;
609 uint leftBits = leftOverBits;
610 uint leftSoFar = (leftOverCount & (uint)0x0F);
611 uint leftSize = ((leftOverCount >> 4) & (uint)0x0F);
613 int byteEnd = byteIndex + byteCount;
614 if (byteEnd < 0 || byteEnd > bytes.Length)
615 throw new SystemException (String.Format ("INTERNAL ERROR: should not happen: {0} {1} {2}", byteIndex, byteCount, byteEnd));
617 for(; byteIndex < byteEnd; byteIndex++) {
618 // Fetch the next character from the byte buffer.
619 ch = (uint)(bytes[byteIndex]);
621 // Process a UTF-8 start character.
622 if (ch < (uint)0x0080) {
623 // Single-byte UTF-8 character.
624 if (posn >= length) {
625 throw new ArgumentException (_("Arg_InsufficientSpace"), "chars");
627 chars[posn++] = (char)ch;
628 } else if ((ch & (uint)0xE0) == (uint)0xC0) {
629 // Double-byte UTF-8 character.
630 leftBits = (ch & (uint)0x1F);
633 } else if ((ch & (uint)0xF0) == (uint)0xE0) {
634 // Three-byte UTF-8 character.
635 leftBits = (ch & (uint)0x0F);
638 } else if ((ch & (uint)0xF8) == (uint)0xF0) {
639 // Four-byte UTF-8 character.
640 leftBits = (ch & (uint)0x07);
643 } else if ((ch & (uint)0xFC) == (uint)0xF8) {
644 // Five-byte UTF-8 character.
645 leftBits = (ch & (uint)0x03);
648 } else if ((ch & (uint)0xFE) == (uint)0xFC) {
649 // Six-byte UTF-8 character.
650 leftBits = (ch & (uint)0x03);
654 // Invalid UTF-8 start character.
656 Fallback (provider, ref fallbackBuffer, bytes, byteIndex, chars, ref posn);
659 throw new ArgumentException (_("Arg_InvalidUTF8"), "bytes");
663 // Process an extra byte in a multi-byte sequence.
664 if ((ch & (uint)0xC0) == (uint)0x80) {
665 leftBits = ((leftBits << 6) | (ch & (uint)0x3F));
666 if (++leftSoFar >= leftSize) {
667 // We have a complete character now.
668 if (leftBits < (uint)0x10000) {
669 // is it an overlong ?
670 bool overlong = false;
673 overlong = (leftBits <= 0x7F);
676 overlong = (leftBits <= 0x07FF);
679 overlong = (leftBits <= 0xFFFF);
682 overlong = (leftBits <= 0x1FFFFF);
685 overlong = (leftBits <= 0x03FFFFFF);
690 Fallback (provider, ref fallbackBuffer, bytes, byteIndex, chars, ref posn);
693 throw new ArgumentException (_("Overlong"), leftBits.ToString ());
696 else if ((leftBits & 0xF800) == 0xD800) {
697 // UTF-8 doesn't use surrogate characters
699 Fallback (provider, ref fallbackBuffer, bytes, byteIndex, chars, ref posn);
702 throw new ArgumentException (_("Arg_InvalidUTF8"), "bytes");
706 if (posn >= length) {
707 throw new ArgumentException
708 (_("Arg_InsufficientSpace"), "chars");
710 chars[posn++] = (char)leftBits;
712 } else if (leftBits < (uint)0x110000) {
713 if ((posn + 2) > length) {
714 throw new ArgumentException
715 (_("Arg_InsufficientSpace"), "chars");
717 leftBits -= (uint)0x10000;
718 chars[posn++] = (char)((leftBits >> 10) +
721 (char)((leftBits & (uint)0x3FF) + (uint)0xDC00);
724 Fallback (provider, ref fallbackBuffer, bytes, byteIndex, chars, ref posn);
727 throw new ArgumentException (_("Arg_InvalidUTF8"), "bytes");
733 // Invalid UTF-8 sequence: clear and restart.
735 Fallback (provider, ref fallbackBuffer, bytes, byteIndex, chars, ref posn);
738 throw new ArgumentException (_("Arg_InvalidUTF8"), "bytes");
745 if (flush && leftSize != 0) {
746 // We had left-over bytes that didn't make up
747 // a complete UTF-8 character sequence.
749 Fallback (provider, ref fallbackBuffer, bytes, byteIndex, chars, ref posn);
752 throw new ArgumentException (_("Arg_InvalidUTF8"), "bytes");
755 leftOverBits = leftBits;
756 leftOverCount = (leftSoFar | (leftSize << 4));
758 // Return the final length to the caller.
759 return posn - charIndex;
762 // Get the characters that result from decoding a byte buffer.
763 public override int GetChars (byte[] bytes, int byteIndex, int byteCount,
764 char[] chars, int charIndex)
766 uint leftOverBits = 0;
767 uint leftOverCount = 0;
769 DecoderFallbackBuffer buf = null;
770 return InternalGetChars (bytes, byteIndex, byteCount, chars,
771 charIndex, ref leftOverBits, ref leftOverCount, DecoderFallback, ref buf, true);
773 return InternalGetChars (bytes, byteIndex, byteCount, chars,
774 charIndex, ref leftOverBits, ref leftOverCount, throwOnInvalid, true);
778 // Get the maximum number of bytes needed to encode a
779 // specified number of characters.
780 public override int GetMaxByteCount (int charCount)
783 throw new ArgumentOutOfRangeException ("charCount", _("ArgRange_NonNegative"));
785 return charCount * 4;
788 // Get the maximum number of characters needed to decode a
789 // specified number of bytes.
790 public override int GetMaxCharCount (int byteCount)
793 throw new ArgumentOutOfRangeException ("byteCount", _("ArgRange_NonNegative"));
798 // Get a UTF8-specific decoder that is attached to this instance.
799 public override Decoder GetDecoder ()
802 return new UTF8Decoder (DecoderFallback);
804 return new UTF8Decoder (throwOnInvalid);
808 // Get a UTF8-specific encoder that is attached to this instance.
809 public override Encoder GetEncoder ()
811 return new UTF8Encoder (emitIdentifier);
814 // Get the UTF8 preamble.
815 public override byte[] GetPreamble ()
817 if (emitIdentifier) {
818 byte[] pre = new byte [3];
828 // Determine if this object is equal to another.
829 public override bool Equals (Object value)
831 UTF8Encoding enc = (value as UTF8Encoding);
834 return (codePage == enc.codePage &&
835 emitIdentifier == enc.emitIdentifier &&
836 DecoderFallback == enc.DecoderFallback &&
837 EncoderFallback == enc.EncoderFallback);
839 return (codePage == enc.codePage &&
840 emitIdentifier == enc.emitIdentifier &&
841 throwOnInvalid == enc.throwOnInvalid);
848 // Get the hash code for this object.
849 public override int GetHashCode ()
851 return base.GetHashCode ();
854 public override byte [] GetBytes (String s)
857 throw new ArgumentNullException ("s");
859 int length = GetByteCount (s);
860 byte [] bytes = new byte [length];
861 GetBytes (s, 0, s.Length, bytes, 0);
865 // UTF-8 decoder implementation.
867 private class UTF8Decoder : Decoder
870 private bool throwOnInvalid;
872 private uint leftOverBits;
873 private uint leftOverCount;
877 public UTF8Decoder (DecoderFallback fallback)
879 public UTF8Decoder (bool throwOnInvalid)
885 this.throwOnInvalid = throwOnInvalid;
891 // Override inherited methods.
892 public override int GetCharCount (byte[] bytes, int index, int count)
895 DecoderFallbackBuffer buf = null;
896 return InternalGetCharCount (bytes, index, count,
897 leftOverBits, leftOverCount, this, ref buf, false);
899 return InternalGetCharCount (bytes, index, count,
900 leftOverBits, leftOverCount, throwOnInvalid, false);
903 public override int GetChars (byte[] bytes, int byteIndex,
904 int byteCount, char[] chars, int charIndex)
907 DecoderFallbackBuffer buf = null;
908 return InternalGetChars (bytes, byteIndex, byteCount,
909 chars, charIndex, ref leftOverBits, ref leftOverCount, this, ref buf, false);
911 return InternalGetChars (bytes, byteIndex, byteCount,
912 chars, charIndex, ref leftOverBits, ref leftOverCount, throwOnInvalid, false);
916 } // class UTF8Decoder
918 // UTF-8 encoder implementation.
920 private class UTF8Encoder : Encoder
922 private bool emitIdentifier;
923 private uint leftOverForCount;
924 private uint leftOverForConv;
927 public UTF8Encoder (bool emitIdentifier)
929 this.emitIdentifier = emitIdentifier;
930 leftOverForCount = 0;
934 // Override inherited methods.
935 public override int GetByteCount (char[] chars, int index,
936 int count, bool flush)
938 return InternalGetByteCount (chars, index, count, ref leftOverForCount, flush);
940 public override int GetBytes (char[] chars, int charIndex,
941 int charCount, byte[] bytes, int byteIndex, bool flush)
944 result = InternalGetBytes (chars, charIndex, charCount, bytes, byteIndex, ref leftOverForConv, flush);
945 emitIdentifier = false;
950 public unsafe override int GetByteCount (char* chars, int count, bool flush)
952 return InternalGetByteCount (chars, count, ref leftOverForCount, flush);
955 public unsafe override int GetBytes (char* chars, int charCount,
956 byte* bytes, int byteCount, bool flush)
959 result = InternalGetBytes (chars, charCount, bytes, byteCount, ref leftOverForConv, flush);
960 emitIdentifier = false;
965 } // class UTF8Encoder
967 }; // class UTF8Encoding
969 }; // namespace System.Text