| File: System\Text\DecoderFallbackBufferHelper.cs | Web Access |
| Project: src\runtime\src\libraries\System.Text.Encoding.CodePages\src\System.Text.Encoding.CodePages.csproj (System.Text.Encoding.CodePages) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; namespace System.Text { internal unsafe struct DecoderFallbackBufferHelper { // Internal items to help us figure out what we're doing as far as error messages, etc. // These help us with our performance and messages internally internal unsafe byte* byteStart; internal unsafe char* charEnd; private readonly DecoderFallbackBuffer? _fallbackBuffer; public DecoderFallbackBufferHelper(DecoderFallbackBuffer? fallbackBuffer) { _fallbackBuffer = fallbackBuffer; byteStart = null; charEnd = null; } internal void InternalReset() { Debug.Assert(_fallbackBuffer != null); byteStart = null; _fallbackBuffer!.Reset(); } internal void InternalInitialize(byte* _byteStart, char* _charEnd) { byteStart = _byteStart; charEnd = _charEnd; } // Fallback the current byte by sticking it into the remaining char buffer. // This can only be called by our encodings (other have to use the public fallback methods), so // we can use our DecoderNLS here too (except we don't). // Returns true if we are successful, false if we can't fallback the character (no buffer space) // So the caller needs to throw buffer space if the method returns false. // Right now this has both bytes and bytes[], since we might have extra bytes, hence the // array, and we might need the index, hence the byte* // Don't touch ref chars unless we succeed internal bool InternalFallback(byte[] bytes, byte* pBytes, ref char* chars) { Debug.Assert(byteStart != null, "[DecoderFallback.InternalFallback]Used InternalFallback without calling InternalInitialize"); Debug.Assert(_fallbackBuffer != null); // See if there's a fallback character and we have an output buffer then copy our string. if (_fallbackBuffer!.Fallback(bytes, (int)(pBytes - byteStart - bytes.Length))) { // Copy the chars to our output char ch; char* charTemp = chars; bool bHighSurrogate = false; while ((ch = _fallbackBuffer.GetNextChar()) != 0) { // Make sure no mixed up surrogates if (char.IsSurrogate(ch)) { if (char.IsHighSurrogate(ch)) { // High Surrogate if (bHighSurrogate) throw new ArgumentException(SR.Argument_InvalidCharSequenceNoIndex); bHighSurrogate = true; } else { // Low surrogate if (!bHighSurrogate) throw new ArgumentException(SR.Argument_InvalidCharSequenceNoIndex); bHighSurrogate = false; } } if (charTemp >= charEnd) { // No buffer space return false; } *(charTemp++) = ch; } // Need to make sure that bHighSurrogate isn't true if (bHighSurrogate) throw new ArgumentException(SR.Argument_InvalidCharSequenceNoIndex); // Now we aren't going to be false, so its OK to update chars chars = charTemp; } return true; } // This version just counts the fallback and doesn't actually copy anything. // Right now this has both bytes and bytes[], since we might have extra bytes, hence the // array, and we might need the index, hence the byte* internal unsafe int InternalFallback(byte[] bytes, byte* pBytes) { Debug.Assert(byteStart != null, "[DecoderFallback.InternalFallback]Used InternalFallback without calling InternalInitialize"); Debug.Assert(_fallbackBuffer != null); // See if there's a fallback character and we have an output buffer then copy our string. if (_fallbackBuffer!.Fallback(bytes, (int)(pBytes - byteStart - bytes.Length))) { int count = 0; char ch; bool bHighSurrogate = false; while ((ch = _fallbackBuffer.GetNextChar()) != 0) { // Make sure no mixed up surrogates if (char.IsSurrogate(ch)) { if (char.IsHighSurrogate(ch)) { // High Surrogate if (bHighSurrogate) throw new ArgumentException(SR.Argument_InvalidCharSequenceNoIndex); bHighSurrogate = true; } else { // Low surrogate if (!bHighSurrogate) throw new ArgumentException(SR.Argument_InvalidCharSequenceNoIndex); bHighSurrogate = false; } } count++; } // Need to make sure that bHighSurrogate isn't true if (bHighSurrogate) throw new ArgumentException(SR.Argument_InvalidCharSequenceNoIndex); return count; } // If no fallback return 0 return 0; } } }