UTF32Encoding.cs 50 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210
  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. // Don't override IsAlwaysNormalized because it is just a Unicode Transformation and could be confused.
  6. //
  7. using System;
  8. using System.Diagnostics;
  9. using System.Globalization;
  10. using System.Runtime.InteropServices;
  11. namespace System.Text
  12. {
  13. // Encodes text into and out of UTF-32. UTF-32 is a way of writing
  14. // Unicode characters with a single storage unit (32 bits) per character,
  15. //
  16. // The UTF-32 byte order mark is simply the Unicode byte order mark
  17. // (0x00FEFF) written in UTF-32 (0x0000FEFF or 0xFFFE0000). The byte order
  18. // mark is used mostly to distinguish UTF-32 text from other encodings, and doesn't
  19. // switch the byte orderings.
  20. public sealed class UTF32Encoding : Encoding
  21. {
  22. /*
  23. words bits UTF-32 representation
  24. ----- ---- -----------------------------------
  25. 1 16 00000000 00000000 xxxxxxxx xxxxxxxx
  26. 2 21 00000000 000xxxxx hhhhhhll llllllll
  27. ----- ---- -----------------------------------
  28. Surrogate:
  29. Real Unicode value = (HighSurrogate - 0xD800) * 0x400 + (LowSurrogate - 0xDC00) + 0x10000
  30. */
  31. // Used by Encoding.UTF32/BigEndianUTF32 for lazy initialization
  32. // The initialization code will not be run until a static member of the class is referenced
  33. internal static readonly UTF32Encoding s_default = new UTF32Encoding(bigEndian: false, byteOrderMark: true);
  34. internal static readonly UTF32Encoding s_bigEndianDefault = new UTF32Encoding(bigEndian: true, byteOrderMark: true);
  35. private readonly bool _emitUTF32ByteOrderMark = false;
  36. private readonly bool _isThrowException = false;
  37. private readonly bool _bigEndian = false;
  38. public UTF32Encoding() : this(false, true)
  39. {
  40. }
  41. public UTF32Encoding(bool bigEndian, bool byteOrderMark) :
  42. base(bigEndian ? 12001 : 12000)
  43. {
  44. _bigEndian = bigEndian;
  45. _emitUTF32ByteOrderMark = byteOrderMark;
  46. }
  47. public UTF32Encoding(bool bigEndian, bool byteOrderMark, bool throwOnInvalidCharacters) :
  48. this(bigEndian, byteOrderMark)
  49. {
  50. _isThrowException = throwOnInvalidCharacters;
  51. // Encoding constructor already did this, but it'll be wrong if we're throwing exceptions
  52. if (_isThrowException)
  53. SetDefaultFallbacks();
  54. }
  55. internal override void SetDefaultFallbacks()
  56. {
  57. // For UTF-X encodings, we use a replacement fallback with an empty string
  58. if (_isThrowException)
  59. {
  60. this.encoderFallback = EncoderFallback.ExceptionFallback;
  61. this.decoderFallback = DecoderFallback.ExceptionFallback;
  62. }
  63. else
  64. {
  65. this.encoderFallback = new EncoderReplacementFallback("\xFFFD");
  66. this.decoderFallback = new DecoderReplacementFallback("\xFFFD");
  67. }
  68. }
  69. // The following methods are copied from EncodingNLS.cs.
  70. // Unfortunately EncodingNLS.cs is internal and we're public, so we have to re-implement them here.
  71. // These should be kept in sync for the following classes:
  72. // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
  73. // Returns the number of bytes required to encode a range of characters in
  74. // a character array.
  75. //
  76. // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
  77. // So if you fix this, fix the others. Currently those include:
  78. // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
  79. // parent method is safe
  80. public override unsafe int GetByteCount(char[] chars, int index, int count)
  81. {
  82. // Validate input parameters
  83. if (chars == null)
  84. throw new ArgumentNullException(nameof(chars), SR.ArgumentNull_Array);
  85. if (index < 0 || count < 0)
  86. throw new ArgumentOutOfRangeException((index < 0 ? nameof(index) : nameof(count)), SR.ArgumentOutOfRange_NeedNonNegNum);
  87. if (chars.Length - index < count)
  88. throw new ArgumentOutOfRangeException(nameof(chars), SR.ArgumentOutOfRange_IndexCountBuffer);
  89. // If no input, return 0, avoid fixed empty array problem
  90. if (count == 0)
  91. return 0;
  92. // Just call the pointer version
  93. fixed (char* pChars = chars)
  94. return GetByteCount(pChars + index, count, null);
  95. }
  96. // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
  97. // So if you fix this, fix the others. Currently those include:
  98. // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
  99. // parent method is safe
  100. public override unsafe int GetByteCount(string s)
  101. {
  102. // Validate input
  103. if (s==null)
  104. throw new ArgumentNullException(nameof(s));
  105. fixed (char* pChars = s)
  106. return GetByteCount(pChars, s.Length, null);
  107. }
  108. // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
  109. // So if you fix this, fix the others. Currently those include:
  110. // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
  111. [CLSCompliant(false)]
  112. public override unsafe int GetByteCount(char* chars, int count)
  113. {
  114. // Validate Parameters
  115. if (chars == null)
  116. throw new ArgumentNullException(nameof(chars), SR.ArgumentNull_Array);
  117. if (count < 0)
  118. throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum);
  119. // Call it with empty encoder
  120. return GetByteCount(chars, count, null);
  121. }
  122. // Parent method is safe.
  123. // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
  124. // So if you fix this, fix the others. Currently those include:
  125. // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
  126. public override unsafe int GetBytes(string s, int charIndex, int charCount,
  127. byte[] bytes, int byteIndex)
  128. {
  129. if (s == null || bytes == null)
  130. throw new ArgumentNullException((s == null ? nameof(s) : nameof(bytes)), SR.ArgumentNull_Array);
  131. if (charIndex < 0 || charCount < 0)
  132. throw new ArgumentOutOfRangeException((charIndex < 0 ? nameof(charIndex) : nameof(charCount)), SR.ArgumentOutOfRange_NeedNonNegNum);
  133. if (s.Length - charIndex < charCount)
  134. throw new ArgumentOutOfRangeException(nameof(s), SR.ArgumentOutOfRange_IndexCount);
  135. if (byteIndex < 0 || byteIndex > bytes.Length)
  136. throw new ArgumentOutOfRangeException(nameof(byteIndex), SR.ArgumentOutOfRange_Index);
  137. int byteCount = bytes.Length - byteIndex;
  138. fixed (char* pChars = s) fixed (byte* pBytes = &MemoryMarshal.GetReference((Span<byte>)bytes))
  139. return GetBytes(pChars + charIndex, charCount, pBytes + byteIndex, byteCount, null);
  140. }
  141. // Encodes a range of characters in a character array into a range of bytes
  142. // in a byte array. An exception occurs if the byte array is not large
  143. // enough to hold the complete encoding of the characters. The
  144. // GetByteCount method can be used to determine the exact number of
  145. // bytes that will be produced for a given range of characters.
  146. // Alternatively, the GetMaxByteCount method can be used to
  147. // determine the maximum number of bytes that will be produced for a given
  148. // number of characters, regardless of the actual character values.
  149. //
  150. // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
  151. // So if you fix this, fix the others. Currently those include:
  152. // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
  153. // parent method is safe
  154. public override unsafe int GetBytes(char[] chars, int charIndex, int charCount,
  155. byte[] bytes, int byteIndex)
  156. {
  157. // Validate parameters
  158. if (chars == null || bytes == null)
  159. throw new ArgumentNullException((chars == null ? nameof(chars) : nameof(bytes)), SR.ArgumentNull_Array);
  160. if (charIndex < 0 || charCount < 0)
  161. throw new ArgumentOutOfRangeException((charIndex < 0 ? nameof(charIndex) : nameof(charCount)), SR.ArgumentOutOfRange_NeedNonNegNum);
  162. if (chars.Length - charIndex < charCount)
  163. throw new ArgumentOutOfRangeException(nameof(chars), SR.ArgumentOutOfRange_IndexCountBuffer);
  164. if (byteIndex < 0 || byteIndex > bytes.Length)
  165. throw new ArgumentOutOfRangeException(nameof(byteIndex), SR.ArgumentOutOfRange_Index);
  166. // If nothing to encode return 0, avoid fixed problem
  167. if (charCount == 0)
  168. return 0;
  169. // Just call pointer version
  170. int byteCount = bytes.Length - byteIndex;
  171. fixed (char* pChars = chars) fixed (byte* pBytes = &MemoryMarshal.GetReference((Span<byte>)bytes))
  172. // Remember that byteCount is # to decode, not size of array.
  173. return GetBytes(pChars + charIndex, charCount, pBytes + byteIndex, byteCount, null);
  174. }
  175. // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
  176. // So if you fix this, fix the others. Currently those include:
  177. // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
  178. [CLSCompliant(false)]
  179. public override unsafe int GetBytes(char* chars, int charCount, byte* bytes, int byteCount)
  180. {
  181. // Validate Parameters
  182. if (bytes == null || chars == null)
  183. throw new ArgumentNullException(bytes == null ? nameof(bytes) : nameof(chars), SR.ArgumentNull_Array);
  184. if (charCount < 0 || byteCount < 0)
  185. throw new ArgumentOutOfRangeException((charCount < 0 ? nameof(charCount) : nameof(byteCount)), SR.ArgumentOutOfRange_NeedNonNegNum);
  186. return GetBytes(chars, charCount, bytes, byteCount, null);
  187. }
  188. // Returns the number of characters produced by decoding a range of bytes
  189. // in a byte array.
  190. //
  191. // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
  192. // So if you fix this, fix the others. Currently those include:
  193. // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
  194. // parent method is safe
  195. public override unsafe int GetCharCount(byte[] bytes, int index, int count)
  196. {
  197. // Validate Parameters
  198. if (bytes == null)
  199. throw new ArgumentNullException(nameof(bytes), SR.ArgumentNull_Array);
  200. if (index < 0 || count < 0)
  201. throw new ArgumentOutOfRangeException((index < 0 ? nameof(index) : nameof(count)), SR.ArgumentOutOfRange_NeedNonNegNum);
  202. if (bytes.Length - index < count)
  203. throw new ArgumentOutOfRangeException(nameof(bytes), SR.ArgumentOutOfRange_IndexCountBuffer);
  204. // If no input just return 0, fixed doesn't like 0 length arrays.
  205. if (count == 0)
  206. return 0;
  207. // Just call pointer version
  208. fixed (byte* pBytes = bytes)
  209. return GetCharCount(pBytes + index, count, null);
  210. }
  211. // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
  212. // So if you fix this, fix the others. Currently those include:
  213. // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
  214. [CLSCompliant(false)]
  215. public override unsafe int GetCharCount(byte* bytes, int count)
  216. {
  217. // Validate Parameters
  218. if (bytes == null)
  219. throw new ArgumentNullException(nameof(bytes), SR.ArgumentNull_Array);
  220. if (count < 0)
  221. throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_NeedNonNegNum);
  222. return GetCharCount(bytes, count, null);
  223. }
  224. // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
  225. // So if you fix this, fix the others. Currently those include:
  226. // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
  227. // parent method is safe
  228. public override unsafe int GetChars(byte[] bytes, int byteIndex, int byteCount,
  229. char[] chars, int charIndex)
  230. {
  231. // Validate Parameters
  232. if (bytes == null || chars == null)
  233. throw new ArgumentNullException(bytes == null ? nameof(bytes) : nameof(chars), SR.ArgumentNull_Array);
  234. if (byteIndex < 0 || byteCount < 0)
  235. throw new ArgumentOutOfRangeException((byteIndex < 0 ? nameof(byteIndex) : nameof(byteCount)), SR.ArgumentOutOfRange_NeedNonNegNum);
  236. if ( bytes.Length - byteIndex < byteCount)
  237. throw new ArgumentOutOfRangeException(nameof(bytes), SR.ArgumentOutOfRange_IndexCountBuffer);
  238. if (charIndex < 0 || charIndex > chars.Length)
  239. throw new ArgumentOutOfRangeException(nameof(charIndex), SR.ArgumentOutOfRange_Index);
  240. // If no input, return 0 & avoid fixed problem
  241. if (byteCount == 0)
  242. return 0;
  243. // Just call pointer version
  244. int charCount = chars.Length - charIndex;
  245. fixed (byte* pBytes = bytes) fixed (char* pChars = &MemoryMarshal.GetReference((Span<char>)chars))
  246. // Remember that charCount is # to decode, not size of array
  247. return GetChars(pBytes + byteIndex, byteCount, pChars + charIndex, charCount, null);
  248. }
  249. // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
  250. // So if you fix this, fix the others. Currently those include:
  251. // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
  252. [CLSCompliant(false)]
  253. public unsafe override int GetChars(byte* bytes, int byteCount, char* chars, int charCount)
  254. {
  255. // Validate Parameters
  256. if (bytes == null || chars == null)
  257. throw new ArgumentNullException(bytes == null ? nameof(bytes) : nameof(chars), SR.ArgumentNull_Array);
  258. if (charCount < 0 || byteCount < 0)
  259. throw new ArgumentOutOfRangeException((charCount < 0 ? nameof(charCount) : nameof(byteCount)), SR.ArgumentOutOfRange_NeedNonNegNum);
  260. return GetChars(bytes, byteCount, chars, charCount, null);
  261. }
  262. // Returns a string containing the decoded representation of a range of
  263. // bytes in a byte array.
  264. //
  265. // All of our public Encodings that don't use EncodingNLS must have this (including EncodingNLS)
  266. // So if you fix this, fix the others. Currently those include:
  267. // EncodingNLS, UTF7Encoding, UTF8Encoding, UTF32Encoding, ASCIIEncoding, UnicodeEncoding
  268. // parent method is safe
  269. public override unsafe string GetString(byte[] bytes, int index, int count)
  270. {
  271. // Validate Parameters
  272. if (bytes == null)
  273. throw new ArgumentNullException(nameof(bytes), SR.ArgumentNull_Array);
  274. if (index < 0 || count < 0)
  275. throw new ArgumentOutOfRangeException((index < 0 ? nameof(index) : nameof(count)), SR.ArgumentOutOfRange_NeedNonNegNum);
  276. if (bytes.Length - index < count)
  277. throw new ArgumentOutOfRangeException(nameof(bytes), SR.ArgumentOutOfRange_IndexCountBuffer);
  278. // Avoid problems with empty input buffer
  279. if (count == 0) return string.Empty;
  280. fixed (byte* pBytes = bytes)
  281. return string.CreateStringFromEncoding(
  282. pBytes + index, count, this);
  283. }
  284. //
  285. // End of standard methods copied from EncodingNLS.cs
  286. //
  287. internal override unsafe int GetByteCount(char* chars, int count, EncoderNLS encoder)
  288. {
  289. Debug.Assert(chars != null, "[UTF32Encoding.GetByteCount]chars!=null");
  290. Debug.Assert(count >= 0, "[UTF32Encoding.GetByteCount]count >=0");
  291. char* end = chars + count;
  292. char* charStart = chars;
  293. int byteCount = 0;
  294. char highSurrogate = '\0';
  295. // For fallback we may need a fallback buffer
  296. EncoderFallbackBuffer fallbackBuffer = null;
  297. char* charsForFallback;
  298. if (encoder != null)
  299. {
  300. highSurrogate = encoder._charLeftOver;
  301. fallbackBuffer = encoder.FallbackBuffer;
  302. // We mustn't have left over fallback data when counting
  303. if (fallbackBuffer.Remaining > 0)
  304. throw new ArgumentException(SR.Format(SR.Argument_EncoderFallbackNotEmpty, this.EncodingName, encoder.Fallback.GetType()));
  305. }
  306. else
  307. {
  308. fallbackBuffer = this.encoderFallback.CreateFallbackBuffer();
  309. }
  310. // Set our internal fallback interesting things.
  311. fallbackBuffer.InternalInitialize(charStart, end, encoder, false);
  312. char ch;
  313. TryAgain:
  314. while (((ch = fallbackBuffer.InternalGetNextChar()) != 0) || chars < end)
  315. {
  316. // First unwind any fallback
  317. if (ch == 0)
  318. {
  319. // No fallback, just get next char
  320. ch = *chars;
  321. chars++;
  322. }
  323. // Do we need a low surrogate?
  324. if (highSurrogate != '\0')
  325. {
  326. //
  327. // In previous char, we encounter a high surrogate, so we are expecting a low surrogate here.
  328. //
  329. if (char.IsLowSurrogate(ch))
  330. {
  331. // They're all legal
  332. highSurrogate = '\0';
  333. //
  334. // One surrogate pair will be translated into 4 bytes UTF32.
  335. //
  336. byteCount += 4;
  337. continue;
  338. }
  339. // We are missing our low surrogate, decrement chars and fallback the high surrogate
  340. // The high surrogate may have come from the encoder, but nothing else did.
  341. Debug.Assert(chars > charStart,
  342. "[UTF32Encoding.GetByteCount]Expected chars to have advanced if no low surrogate");
  343. chars--;
  344. // Do the fallback
  345. charsForFallback = chars;
  346. fallbackBuffer.InternalFallback(highSurrogate, ref charsForFallback);
  347. chars = charsForFallback;
  348. // We're going to fallback the old high surrogate.
  349. highSurrogate = '\0';
  350. continue;
  351. }
  352. // Do we have another high surrogate?
  353. if (char.IsHighSurrogate(ch))
  354. {
  355. //
  356. // We'll have a high surrogate to check next time.
  357. //
  358. highSurrogate = ch;
  359. continue;
  360. }
  361. // Check for illegal characters
  362. if (char.IsLowSurrogate(ch))
  363. {
  364. // We have a leading low surrogate, do the fallback
  365. charsForFallback = chars;
  366. fallbackBuffer.InternalFallback(ch, ref charsForFallback);
  367. chars = charsForFallback;
  368. // Try again with fallback buffer
  369. continue;
  370. }
  371. // We get to add the character (4 bytes UTF32)
  372. byteCount += 4;
  373. }
  374. // May have to do our last surrogate
  375. if ((encoder == null || encoder.MustFlush) && highSurrogate > 0)
  376. {
  377. // We have to do the fallback for the lonely high surrogate
  378. charsForFallback = chars;
  379. fallbackBuffer.InternalFallback(highSurrogate, ref charsForFallback);
  380. chars = charsForFallback;
  381. highSurrogate = (char)0;
  382. goto TryAgain;
  383. }
  384. // Check for overflows.
  385. if (byteCount < 0)
  386. throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_GetByteCountOverflow);
  387. // Shouldn't have anything in fallback buffer for GetByteCount
  388. // (don't have to check _throwOnOverflow for count)
  389. Debug.Assert(fallbackBuffer.Remaining == 0,
  390. "[UTF32Encoding.GetByteCount]Expected empty fallback buffer at end");
  391. // Return our count
  392. return byteCount;
  393. }
  394. internal override unsafe int GetBytes(char* chars, int charCount,
  395. byte* bytes, int byteCount, EncoderNLS encoder)
  396. {
  397. Debug.Assert(chars != null, "[UTF32Encoding.GetBytes]chars!=null");
  398. Debug.Assert(bytes != null, "[UTF32Encoding.GetBytes]bytes!=null");
  399. Debug.Assert(byteCount >= 0, "[UTF32Encoding.GetBytes]byteCount >=0");
  400. Debug.Assert(charCount >= 0, "[UTF32Encoding.GetBytes]charCount >=0");
  401. char* charStart = chars;
  402. char* charEnd = chars + charCount;
  403. byte* byteStart = bytes;
  404. byte* byteEnd = bytes + byteCount;
  405. char highSurrogate = '\0';
  406. // For fallback we may need a fallback buffer
  407. EncoderFallbackBuffer fallbackBuffer = null;
  408. char* charsForFallback;
  409. if (encoder != null)
  410. {
  411. highSurrogate = encoder._charLeftOver;
  412. fallbackBuffer = encoder.FallbackBuffer;
  413. // We mustn't have left over fallback data when not converting
  414. if (encoder._throwOnOverflow && fallbackBuffer.Remaining > 0)
  415. throw new ArgumentException(SR.Format(SR.Argument_EncoderFallbackNotEmpty, this.EncodingName, encoder.Fallback.GetType()));
  416. }
  417. else
  418. {
  419. fallbackBuffer = this.encoderFallback.CreateFallbackBuffer();
  420. }
  421. // Set our internal fallback interesting things.
  422. fallbackBuffer.InternalInitialize(charStart, charEnd, encoder, true);
  423. char ch;
  424. TryAgain:
  425. while (((ch = fallbackBuffer.InternalGetNextChar()) != 0) || chars < charEnd)
  426. {
  427. // First unwind any fallback
  428. if (ch == 0)
  429. {
  430. // No fallback, just get next char
  431. ch = *chars;
  432. chars++;
  433. }
  434. // Do we need a low surrogate?
  435. if (highSurrogate != '\0')
  436. {
  437. //
  438. // In previous char, we encountered a high surrogate, so we are expecting a low surrogate here.
  439. //
  440. if (char.IsLowSurrogate(ch))
  441. {
  442. // Is it a legal one?
  443. uint iTemp = GetSurrogate(highSurrogate, ch);
  444. highSurrogate = '\0';
  445. //
  446. // One surrogate pair will be translated into 4 bytes UTF32.
  447. //
  448. if (bytes + 3 >= byteEnd)
  449. {
  450. // Don't have 4 bytes
  451. if (fallbackBuffer.bFallingBack)
  452. {
  453. fallbackBuffer.MovePrevious(); // Aren't using these 2 fallback chars
  454. fallbackBuffer.MovePrevious();
  455. }
  456. else
  457. {
  458. // If we don't have enough room, then either we should've advanced a while
  459. // or we should have bytes==byteStart and throw below
  460. Debug.Assert(chars > charStart + 1 || bytes == byteStart,
  461. "[UnicodeEncoding.GetBytes]Expected chars to have when no room to add surrogate pair");
  462. chars -= 2; // Aren't using those 2 chars
  463. }
  464. ThrowBytesOverflow(encoder, bytes == byteStart); // Throw maybe (if no bytes written)
  465. highSurrogate = (char)0; // Nothing left over (we backed up to start of pair if supplimentary)
  466. break;
  467. }
  468. if (_bigEndian)
  469. {
  470. *(bytes++) = (byte)(0x00);
  471. *(bytes++) = (byte)(iTemp >> 16); // Implies & 0xFF, which isn't needed cause high are all 0
  472. *(bytes++) = (byte)(iTemp >> 8); // Implies & 0xFF
  473. *(bytes++) = (byte)(iTemp); // Implies & 0xFF
  474. }
  475. else
  476. {
  477. *(bytes++) = (byte)(iTemp); // Implies & 0xFF
  478. *(bytes++) = (byte)(iTemp >> 8); // Implies & 0xFF
  479. *(bytes++) = (byte)(iTemp >> 16); // Implies & 0xFF, which isn't needed cause high are all 0
  480. *(bytes++) = (byte)(0x00);
  481. }
  482. continue;
  483. }
  484. // We are missing our low surrogate, decrement chars and fallback the high surrogate
  485. // The high surrogate may have come from the encoder, but nothing else did.
  486. Debug.Assert(chars > charStart,
  487. "[UTF32Encoding.GetBytes]Expected chars to have advanced if no low surrogate");
  488. chars--;
  489. // Do the fallback
  490. charsForFallback = chars;
  491. fallbackBuffer.InternalFallback(highSurrogate, ref charsForFallback);
  492. chars = charsForFallback;
  493. // We're going to fallback the old high surrogate.
  494. highSurrogate = '\0';
  495. continue;
  496. }
  497. // Do we have another high surrogate?, if so remember it
  498. if (char.IsHighSurrogate(ch))
  499. {
  500. //
  501. // We'll have a high surrogate to check next time.
  502. //
  503. highSurrogate = ch;
  504. continue;
  505. }
  506. // Check for illegal characters (low surrogate)
  507. if (char.IsLowSurrogate(ch))
  508. {
  509. // We have a leading low surrogate, do the fallback
  510. charsForFallback = chars;
  511. fallbackBuffer.InternalFallback(ch, ref charsForFallback);
  512. chars = charsForFallback;
  513. // Try again with fallback buffer
  514. continue;
  515. }
  516. // We get to add the character, yippee.
  517. if (bytes + 3 >= byteEnd)
  518. {
  519. // Don't have 4 bytes
  520. if (fallbackBuffer.bFallingBack)
  521. fallbackBuffer.MovePrevious(); // Aren't using this fallback char
  522. else
  523. {
  524. // Must've advanced already
  525. Debug.Assert(chars > charStart,
  526. "[UTF32Encoding.GetBytes]Expected chars to have advanced if normal character");
  527. chars--; // Aren't using this char
  528. }
  529. ThrowBytesOverflow(encoder, bytes == byteStart); // Throw maybe (if no bytes written)
  530. break; // Didn't throw, stop
  531. }
  532. if (_bigEndian)
  533. {
  534. *(bytes++) = (byte)(0x00);
  535. *(bytes++) = (byte)(0x00);
  536. *(bytes++) = (byte)((uint)ch >> 8); // Implies & 0xFF
  537. *(bytes++) = (byte)(ch); // Implies & 0xFF
  538. }
  539. else
  540. {
  541. *(bytes++) = (byte)(ch); // Implies & 0xFF
  542. *(bytes++) = (byte)((uint)ch >> 8); // Implies & 0xFF
  543. *(bytes++) = (byte)(0x00);
  544. *(bytes++) = (byte)(0x00);
  545. }
  546. }
  547. // May have to do our last surrogate
  548. if ((encoder == null || encoder.MustFlush) && highSurrogate > 0)
  549. {
  550. // We have to do the fallback for the lonely high surrogate
  551. charsForFallback = chars;
  552. fallbackBuffer.InternalFallback(highSurrogate, ref charsForFallback);
  553. chars = charsForFallback;
  554. highSurrogate = (char)0;
  555. goto TryAgain;
  556. }
  557. // Fix our encoder if we have one
  558. Debug.Assert(highSurrogate == 0 || (encoder != null && !encoder.MustFlush),
  559. "[UTF32Encoding.GetBytes]Expected encoder to be flushed.");
  560. if (encoder != null)
  561. {
  562. // Remember our left over surrogate (or 0 if flushing)
  563. encoder._charLeftOver = highSurrogate;
  564. // Need # chars used
  565. encoder._charsUsed = (int)(chars - charStart);
  566. }
  567. // return the new length
  568. return (int)(bytes - byteStart);
  569. }
  570. internal override unsafe int GetCharCount(byte* bytes, int count, DecoderNLS baseDecoder)
  571. {
  572. Debug.Assert(bytes != null, "[UTF32Encoding.GetCharCount]bytes!=null");
  573. Debug.Assert(count >= 0, "[UTF32Encoding.GetCharCount]count >=0");
  574. UTF32Decoder decoder = (UTF32Decoder)baseDecoder;
  575. // None so far!
  576. int charCount = 0;
  577. byte* end = bytes + count;
  578. byte* byteStart = bytes;
  579. // Set up decoder
  580. int readCount = 0;
  581. uint iChar = 0;
  582. // For fallback we may need a fallback buffer
  583. DecoderFallbackBuffer fallbackBuffer = null;
  584. // See if there's anything in our decoder
  585. if (decoder != null)
  586. {
  587. readCount = decoder.readByteCount;
  588. iChar = (uint)decoder.iChar;
  589. fallbackBuffer = decoder.FallbackBuffer;
  590. // Shouldn't have anything in fallback buffer for GetCharCount
  591. // (don't have to check _throwOnOverflow for chars or count)
  592. Debug.Assert(fallbackBuffer.Remaining == 0,
  593. "[UTF32Encoding.GetCharCount]Expected empty fallback buffer at start");
  594. }
  595. else
  596. {
  597. fallbackBuffer = this.decoderFallback.CreateFallbackBuffer();
  598. }
  599. // Set our internal fallback interesting things.
  600. fallbackBuffer.InternalInitialize(byteStart, null);
  601. // Loop through our input, 4 characters at a time!
  602. while (bytes < end && charCount >= 0)
  603. {
  604. // Get our next character
  605. if (_bigEndian)
  606. {
  607. // Scoot left and add it to the bottom
  608. iChar <<= 8;
  609. iChar += *(bytes++);
  610. }
  611. else
  612. {
  613. // Scoot right and add it to the top
  614. iChar >>= 8;
  615. iChar += (uint)(*(bytes++)) << 24;
  616. }
  617. readCount++;
  618. // See if we have all the bytes yet
  619. if (readCount < 4)
  620. continue;
  621. // Have the bytes
  622. readCount = 0;
  623. // See if its valid to encode
  624. if (iChar > 0x10FFFF || (iChar >= 0xD800 && iChar <= 0xDFFF))
  625. {
  626. // Need to fall back these 4 bytes
  627. byte[] fallbackBytes;
  628. if (_bigEndian)
  629. {
  630. fallbackBytes = new byte[] {
  631. unchecked((byte)(iChar>>24)), unchecked((byte)(iChar>>16)),
  632. unchecked((byte)(iChar>>8)), unchecked((byte)(iChar)) };
  633. }
  634. else
  635. {
  636. fallbackBytes = new byte[] {
  637. unchecked((byte)(iChar)), unchecked((byte)(iChar>>8)),
  638. unchecked((byte)(iChar>>16)), unchecked((byte)(iChar>>24)) };
  639. }
  640. charCount += fallbackBuffer.InternalFallback(fallbackBytes, bytes);
  641. // Ignore the illegal character
  642. iChar = 0;
  643. continue;
  644. }
  645. // Ok, we have something we can add to our output
  646. if (iChar >= 0x10000)
  647. {
  648. // Surrogates take 2
  649. charCount++;
  650. }
  651. // Add the rest of the surrogate or our normal character
  652. charCount++;
  653. // iChar is back to 0
  654. iChar = 0;
  655. }
  656. // See if we have something left over that has to be decoded
  657. if (readCount > 0 && (decoder == null || decoder.MustFlush))
  658. {
  659. // Oops, there's something left over with no place to go.
  660. byte[] fallbackBytes = new byte[readCount];
  661. if (_bigEndian)
  662. {
  663. while (readCount > 0)
  664. {
  665. fallbackBytes[--readCount] = unchecked((byte)iChar);
  666. iChar >>= 8;
  667. }
  668. }
  669. else
  670. {
  671. while (readCount > 0)
  672. {
  673. fallbackBytes[--readCount] = unchecked((byte)(iChar >> 24));
  674. iChar <<= 8;
  675. }
  676. }
  677. charCount += fallbackBuffer.InternalFallback(fallbackBytes, bytes);
  678. }
  679. // Check for overflows.
  680. if (charCount < 0)
  681. throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_GetByteCountOverflow);
  682. // Shouldn't have anything in fallback buffer for GetCharCount
  683. // (don't have to check _throwOnOverflow for chars or count)
  684. Debug.Assert(fallbackBuffer.Remaining == 0,
  685. "[UTF32Encoding.GetCharCount]Expected empty fallback buffer at end");
  686. // Return our count
  687. return charCount;
  688. }
  689. internal override unsafe int GetChars(byte* bytes, int byteCount,
  690. char* chars, int charCount, DecoderNLS baseDecoder)
  691. {
  692. Debug.Assert(chars != null, "[UTF32Encoding.GetChars]chars!=null");
  693. Debug.Assert(bytes != null, "[UTF32Encoding.GetChars]bytes!=null");
  694. Debug.Assert(byteCount >= 0, "[UTF32Encoding.GetChars]byteCount >=0");
  695. Debug.Assert(charCount >= 0, "[UTF32Encoding.GetChars]charCount >=0");
  696. UTF32Decoder decoder = (UTF32Decoder)baseDecoder;
  697. // None so far!
  698. char* charStart = chars;
  699. char* charEnd = chars + charCount;
  700. byte* byteStart = bytes;
  701. byte* byteEnd = bytes + byteCount;
  702. // See if there's anything in our decoder (but don't clear it yet)
  703. int readCount = 0;
  704. uint iChar = 0;
  705. // For fallback we may need a fallback buffer
  706. DecoderFallbackBuffer fallbackBuffer = null;
  707. char* charsForFallback;
  708. // See if there's anything in our decoder
  709. if (decoder != null)
  710. {
  711. readCount = decoder.readByteCount;
  712. iChar = (uint)decoder.iChar;
  713. fallbackBuffer = baseDecoder.FallbackBuffer;
  714. // Shouldn't have anything in fallback buffer for GetChars
  715. // (don't have to check _throwOnOverflow for chars)
  716. Debug.Assert(fallbackBuffer.Remaining == 0,
  717. "[UTF32Encoding.GetChars]Expected empty fallback buffer at start");
  718. }
  719. else
  720. {
  721. fallbackBuffer = this.decoderFallback.CreateFallbackBuffer();
  722. }
  723. // Set our internal fallback interesting things.
  724. fallbackBuffer.InternalInitialize(bytes, chars + charCount);
  725. // Loop through our input, 4 characters at a time!
  726. while (bytes < byteEnd)
  727. {
  728. // Get our next character
  729. if (_bigEndian)
  730. {
  731. // Scoot left and add it to the bottom
  732. iChar <<= 8;
  733. iChar += *(bytes++);
  734. }
  735. else
  736. {
  737. // Scoot right and add it to the top
  738. iChar >>= 8;
  739. iChar += (uint)(*(bytes++)) << 24;
  740. }
  741. readCount++;
  742. // See if we have all the bytes yet
  743. if (readCount < 4)
  744. continue;
  745. // Have the bytes
  746. readCount = 0;
  747. // See if its valid to encode
  748. if (iChar > 0x10FFFF || (iChar >= 0xD800 && iChar <= 0xDFFF))
  749. {
  750. // Need to fall back these 4 bytes
  751. byte[] fallbackBytes;
  752. if (_bigEndian)
  753. {
  754. fallbackBytes = new byte[] {
  755. unchecked((byte)(iChar>>24)), unchecked((byte)(iChar>>16)),
  756. unchecked((byte)(iChar>>8)), unchecked((byte)(iChar)) };
  757. }
  758. else
  759. {
  760. fallbackBytes = new byte[] {
  761. unchecked((byte)(iChar)), unchecked((byte)(iChar>>8)),
  762. unchecked((byte)(iChar>>16)), unchecked((byte)(iChar>>24)) };
  763. }
  764. // Chars won't be updated unless this works.
  765. charsForFallback = chars;
  766. bool fallbackResult = fallbackBuffer.InternalFallback(fallbackBytes, bytes, ref charsForFallback);
  767. chars = charsForFallback;
  768. if (!fallbackResult)
  769. {
  770. // Couldn't fallback, throw or wait til next time
  771. // We either read enough bytes for bytes-=4 to work, or we're
  772. // going to throw in ThrowCharsOverflow because chars == charStart
  773. Debug.Assert(bytes >= byteStart + 4 || chars == charStart,
  774. "[UTF32Encoding.GetChars]Expected to have consumed bytes or throw (bad surrogate)");
  775. bytes -= 4; // get back to where we were
  776. iChar = 0; // Remembering nothing
  777. fallbackBuffer.InternalReset();
  778. ThrowCharsOverflow(decoder, chars == charStart);// Might throw, if no chars output
  779. break; // Stop here, didn't throw
  780. }
  781. // Ignore the illegal character
  782. iChar = 0;
  783. continue;
  784. }
  785. // Ok, we have something we can add to our output
  786. if (iChar >= 0x10000)
  787. {
  788. // Surrogates take 2
  789. if (chars >= charEnd - 1)
  790. {
  791. // Throwing or stopping
  792. // We either read enough bytes for bytes-=4 to work, or we're
  793. // going to throw in ThrowCharsOverflow because chars == charStart
  794. Debug.Assert(bytes >= byteStart + 4 || chars == charStart,
  795. "[UTF32Encoding.GetChars]Expected to have consumed bytes or throw (surrogate)");
  796. bytes -= 4; // get back to where we were
  797. iChar = 0; // Remembering nothing
  798. ThrowCharsOverflow(decoder, chars == charStart);// Might throw, if no chars output
  799. break; // Stop here, didn't throw
  800. }
  801. *(chars++) = GetHighSurrogate(iChar);
  802. iChar = GetLowSurrogate(iChar);
  803. }
  804. // Bounds check for normal character
  805. else if (chars >= charEnd)
  806. {
  807. // Throwing or stopping
  808. // We either read enough bytes for bytes-=4 to work, or we're
  809. // going to throw in ThrowCharsOverflow because chars == charStart
  810. Debug.Assert(bytes >= byteStart + 4 || chars == charStart,
  811. "[UTF32Encoding.GetChars]Expected to have consumed bytes or throw (normal char)");
  812. bytes -= 4; // get back to where we were
  813. iChar = 0; // Remembering nothing
  814. ThrowCharsOverflow(decoder, chars == charStart);// Might throw, if no chars output
  815. break; // Stop here, didn't throw
  816. }
  817. // Add the rest of the surrogate or our normal character
  818. *(chars++) = (char)iChar;
  819. // iChar is back to 0
  820. iChar = 0;
  821. }
  822. // See if we have something left over that has to be decoded
  823. if (readCount > 0 && (decoder == null || decoder.MustFlush))
  824. {
  825. // Oops, there's something left over with no place to go.
  826. byte[] fallbackBytes = new byte[readCount];
  827. int tempCount = readCount;
  828. if (_bigEndian)
  829. {
  830. while (tempCount > 0)
  831. {
  832. fallbackBytes[--tempCount] = unchecked((byte)iChar);
  833. iChar >>= 8;
  834. }
  835. }
  836. else
  837. {
  838. while (tempCount > 0)
  839. {
  840. fallbackBytes[--tempCount] = unchecked((byte)(iChar >> 24));
  841. iChar <<= 8;
  842. }
  843. }
  844. charsForFallback = chars;
  845. bool fallbackResult = fallbackBuffer.InternalFallback(fallbackBytes, bytes, ref charsForFallback);
  846. chars = charsForFallback;
  847. if (!fallbackResult)
  848. {
  849. // Couldn't fallback.
  850. fallbackBuffer.InternalReset();
  851. ThrowCharsOverflow(decoder, chars == charStart);// Might throw, if no chars output
  852. // Stop here, didn't throw, backed up, so still nothing in buffer
  853. }
  854. else
  855. {
  856. // Don't clear our decoder unless we could fall it back.
  857. // If we caught the if above, then we're a convert() and will catch this next time.
  858. readCount = 0;
  859. iChar = 0;
  860. }
  861. }
  862. // Remember any left over stuff, clearing buffer as well for MustFlush
  863. if (decoder != null)
  864. {
  865. decoder.iChar = (int)iChar;
  866. decoder.readByteCount = readCount;
  867. decoder._bytesUsed = (int)(bytes - byteStart);
  868. }
  869. // Shouldn't have anything in fallback buffer for GetChars
  870. // (don't have to check _throwOnOverflow for chars)
  871. Debug.Assert(fallbackBuffer.Remaining == 0,
  872. "[UTF32Encoding.GetChars]Expected empty fallback buffer at end");
  873. // Return our count
  874. return (int)(chars - charStart);
  875. }
  876. private uint GetSurrogate(char cHigh, char cLow)
  877. {
  878. return (((uint)cHigh - 0xD800) * 0x400) + ((uint)cLow - 0xDC00) + 0x10000;
  879. }
  880. private char GetHighSurrogate(uint iChar)
  881. {
  882. return (char)((iChar - 0x10000) / 0x400 + 0xD800);
  883. }
  884. private char GetLowSurrogate(uint iChar)
  885. {
  886. return (char)((iChar - 0x10000) % 0x400 + 0xDC00);
  887. }
  888. public override Decoder GetDecoder()
  889. {
  890. return new UTF32Decoder(this);
  891. }
  892. public override Encoder GetEncoder()
  893. {
  894. return new EncoderNLS(this);
  895. }
  896. public override int GetMaxByteCount(int charCount)
  897. {
  898. if (charCount < 0)
  899. throw new ArgumentOutOfRangeException(nameof(charCount),
  900. SR.ArgumentOutOfRange_NeedNonNegNum);
  901. // Characters would be # of characters + 1 in case left over high surrogate is ? * max fallback
  902. long byteCount = (long)charCount + 1;
  903. if (EncoderFallback.MaxCharCount > 1)
  904. byteCount *= EncoderFallback.MaxCharCount;
  905. // 4 bytes per char
  906. byteCount *= 4;
  907. if (byteCount > 0x7fffffff)
  908. throw new ArgumentOutOfRangeException(nameof(charCount), SR.ArgumentOutOfRange_GetByteCountOverflow);
  909. return (int)byteCount;
  910. }
  911. public override int GetMaxCharCount(int byteCount)
  912. {
  913. if (byteCount < 0)
  914. throw new ArgumentOutOfRangeException(nameof(byteCount),
  915. SR.ArgumentOutOfRange_NeedNonNegNum);
  916. // A supplementary character becomes 2 surrogate characters, so 4 input bytes becomes 2 chars,
  917. // plus we may have 1 surrogate char left over if the decoder has 3 bytes in it already for a non-bmp char.
  918. // Have to add another one because 1/2 == 0, but 3 bytes left over could be 2 char surrogate pair
  919. int charCount = (byteCount / 2) + 2;
  920. // Also consider fallback because our input bytes could be out of range of unicode.
  921. // Since fallback would fallback 4 bytes at a time, we'll only fall back 1/2 of MaxCharCount.
  922. if (DecoderFallback.MaxCharCount > 2)
  923. {
  924. // Multiply time fallback size
  925. charCount *= DecoderFallback.MaxCharCount;
  926. // We were already figuring 2 chars per 4 bytes, but fallback will be different #
  927. charCount /= 2;
  928. }
  929. if (charCount > 0x7fffffff)
  930. throw new ArgumentOutOfRangeException(nameof(byteCount), SR.ArgumentOutOfRange_GetCharCountOverflow);
  931. return (int)charCount;
  932. }
  933. public override byte[] GetPreamble()
  934. {
  935. if (_emitUTF32ByteOrderMark)
  936. {
  937. // Allocate new array to prevent users from modifying it.
  938. if (_bigEndian)
  939. {
  940. return new byte[4] { 0x00, 0x00, 0xFE, 0xFF };
  941. }
  942. else
  943. {
  944. return new byte[4] { 0xFF, 0xFE, 0x00, 0x00 }; // 00 00 FE FF
  945. }
  946. }
  947. else
  948. return Array.Empty<byte>();
  949. }
  950. public override ReadOnlySpan<byte> Preamble =>
  951. GetType() != typeof(UTF32Encoding) ? new ReadOnlySpan<byte>(GetPreamble()) : // in case a derived UTF32Encoding overrode GetPreamble
  952. !_emitUTF32ByteOrderMark ? default :
  953. _bigEndian ? (ReadOnlySpan<byte>)new byte[4] { 0x00, 0x00, 0xFE, 0xFF } : // uses C# compiler's optimization for static byte[] data
  954. (ReadOnlySpan<byte>)new byte[4] { 0xFF, 0xFE, 0x00, 0x00 };
  955. public override bool Equals(object value)
  956. {
  957. if (value is UTF32Encoding that)
  958. {
  959. return (_emitUTF32ByteOrderMark == that._emitUTF32ByteOrderMark) &&
  960. (_bigEndian == that._bigEndian) &&
  961. (EncoderFallback.Equals(that.EncoderFallback)) &&
  962. (DecoderFallback.Equals(that.DecoderFallback));
  963. }
  964. return (false);
  965. }
  966. public override int GetHashCode()
  967. {
  968. //Not great distribution, but this is relatively unlikely to be used as the key in a hashtable.
  969. return this.EncoderFallback.GetHashCode() + this.DecoderFallback.GetHashCode() +
  970. CodePage + (_emitUTF32ByteOrderMark ? 4 : 0) + (_bigEndian ? 8 : 0);
  971. }
  972. private sealed class UTF32Decoder : DecoderNLS
  973. {
  974. // Need a place to store any extra bytes we may have picked up
  975. internal int iChar = 0;
  976. internal int readByteCount = 0;
  977. public UTF32Decoder(UTF32Encoding encoding) : base(encoding)
  978. {
  979. // base calls reset
  980. }
  981. public override void Reset()
  982. {
  983. this.iChar = 0;
  984. this.readByteCount = 0;
  985. if (_fallbackBuffer != null)
  986. _fallbackBuffer.Reset();
  987. }
  988. // Anything left in our decoder?
  989. internal override bool HasState
  990. {
  991. get
  992. {
  993. // ReadByteCount is our flag. (iChar==0 doesn't mean much).
  994. return (this.readByteCount != 0);
  995. }
  996. }
  997. }
  998. }
  999. }