| File: System\Xml\Core\XmlCharCheckingReaderAsync.cs | Web Access |
| Project: src\runtime\src\libraries\System.Private.Xml\src\System.Private.Xml.csproj (System.Private.Xml) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Threading.Tasks; using System.Xml; namespace System.Xml { // // XmlCharCheckingReaderWithNS // internal partial class XmlCharCheckingReader : XmlWrappingReader { public override async Task<bool> ReadAsync() { switch (_state) { case State.Initial: _state = State.Interactive; if (base.reader.ReadState == ReadState.Initial) { goto case State.Interactive; } break; case State.Error: return false; case State.InReadBinary: _state = State.Interactive; if (_readBinaryHelper != null) { await _readBinaryHelper.FinishAsync().ConfigureAwait(false); } _state = State.Interactive; goto case State.Interactive; case State.Interactive: if (!await base.reader.ReadAsync().ConfigureAwait(false)) { return false; } break; default: Debug.Fail($"Unexpected state {_state}"); return false; } XmlNodeType nodeType = base.reader.NodeType; if (!_checkCharacters) { switch (nodeType) { case XmlNodeType.Comment: if (_ignoreComments) { return await ReadAsync().ConfigureAwait(false); } break; case XmlNodeType.Whitespace: if (_ignoreWhitespace) { return await ReadAsync().ConfigureAwait(false); } break; case XmlNodeType.ProcessingInstruction: if (_ignorePis) { return await ReadAsync().ConfigureAwait(false); } break; case XmlNodeType.DocumentType: if (_dtdProcessing == DtdProcessing.Prohibit) { Throw(SR.Xml_DtdIsProhibitedEx, string.Empty); } else if (_dtdProcessing == DtdProcessing.Ignore) { return await ReadAsync().ConfigureAwait(false); } break; } return true; } else { switch (nodeType) { case XmlNodeType.Element: if (_checkCharacters) { // check element name ValidateQName(base.reader.Prefix, base.reader.LocalName); // check values of attributes if (base.reader.MoveToFirstAttribute()) { do { ValidateQName(base.reader.Prefix, base.reader.LocalName); CheckCharacters(base.reader.Value); } while (base.reader.MoveToNextAttribute()); base.reader.MoveToElement(); } } break; case XmlNodeType.Text: case XmlNodeType.CDATA: if (_checkCharacters) { CheckCharacters(await base.reader.GetValueAsync().ConfigureAwait(false)); } break; case XmlNodeType.EntityReference: if (_checkCharacters) { // check name ValidateQName(base.reader.Name); } break; case XmlNodeType.ProcessingInstruction: if (_ignorePis) { return await ReadAsync().ConfigureAwait(false); } if (_checkCharacters) { ValidateQName(base.reader.Name); CheckCharacters(base.reader.Value); } break; case XmlNodeType.Comment: if (_ignoreComments) { return await ReadAsync().ConfigureAwait(false); } if (_checkCharacters) { CheckCharacters(base.reader.Value); } break; case XmlNodeType.DocumentType: if (_dtdProcessing == DtdProcessing.Prohibit) { Throw(SR.Xml_DtdIsProhibitedEx, string.Empty); } else if (_dtdProcessing == DtdProcessing.Ignore) { return await ReadAsync().ConfigureAwait(false); } if (_checkCharacters) { ValidateQName(base.reader.Name); CheckCharacters(base.reader.Value); string? str = base.reader.GetAttribute("SYSTEM"); if (str != null) { CheckCharacters(str); } str = base.reader.GetAttribute("PUBLIC"); if (str != null) { int i; if ((i = XmlCharType.IsPublicId(str)) >= 0) { Throw(SR.Xml_InvalidCharacter, XmlException.BuildCharExceptionArgs(str, i)); } } } break; case XmlNodeType.Whitespace: if (_ignoreWhitespace) { return await ReadAsync().ConfigureAwait(false); } if (_checkCharacters) { CheckWhitespace(await base.reader.GetValueAsync().ConfigureAwait(false)); } break; case XmlNodeType.SignificantWhitespace: if (_checkCharacters) { CheckWhitespace(await base.reader.GetValueAsync().ConfigureAwait(false)); } break; case XmlNodeType.EndElement: if (_checkCharacters) { ValidateQName(base.reader.Prefix, base.reader.LocalName); } break; default: break; } _lastNodeType = nodeType; return true; } } public override async Task<int> ReadContentAsBase64Async(byte[] buffer, int index, int count) { if (ReadState != ReadState.Interactive) { return 0; } if (_state != State.InReadBinary) { // forward ReadBase64Chunk calls into the base (wrapped) reader if possible, i.e. if it can read binary and we // should not check characters if (base.CanReadBinaryContent && (!_checkCharacters)) { _readBinaryHelper = null; _state = State.InReadBinary; return await base.ReadContentAsBase64Async(buffer, index, count).ConfigureAwait(false); } // the wrapped reader cannot read chunks or we are on an element where we should check characters or ignore whitespace else { _readBinaryHelper = ReadContentAsBinaryHelper.CreateOrReset(_readBinaryHelper, this); } } else { // forward calls into wrapped reader if (_readBinaryHelper == null) { return await base.ReadContentAsBase64Async(buffer, index, count).ConfigureAwait(false); } } // turn off InReadBinary state in order to have a normal Read() behavior when called from readBinaryHelper _state = State.Interactive; // call to the helper int readCount = await _readBinaryHelper.ReadContentAsBase64Async(buffer, index, count).ConfigureAwait(false); // turn on InReadBinary in again and return _state = State.InReadBinary; return readCount; } public override async Task<int> ReadContentAsBinHexAsync(byte[] buffer, int index, int count) { if (ReadState != ReadState.Interactive) { return 0; } if (_state != State.InReadBinary) { // forward ReadBinHexChunk calls into the base (wrapped) reader if possible, i.e. if it can read chunks and we // should not check characters if (base.CanReadBinaryContent && (!_checkCharacters)) { _readBinaryHelper = null; _state = State.InReadBinary; return await base.ReadContentAsBinHexAsync(buffer, index, count).ConfigureAwait(false); } // the wrapped reader cannot read chunks or we are on an element where we should check characters or ignore whitespace else { _readBinaryHelper = ReadContentAsBinaryHelper.CreateOrReset(_readBinaryHelper, this); } } else { // forward calls into wrapped reader if (_readBinaryHelper == null) { return await base.ReadContentAsBinHexAsync(buffer, index, count).ConfigureAwait(false); } } // turn off InReadBinary state in order to have a normal Read() behavior when called from readBinaryHelper _state = State.Interactive; // call to the helper int readCount = await _readBinaryHelper.ReadContentAsBinHexAsync(buffer, index, count).ConfigureAwait(false); // turn on InReadBinary in again and return _state = State.InReadBinary; return readCount; } public override Task<int> ReadElementContentAsBase64Async(byte[] buffer, int index, int count) { ArgumentNullException.ThrowIfNull(buffer); if (index < 0 || (uint)count > buffer.Length - index) { throw new ArgumentOutOfRangeException(index < 0 ? nameof(index) : nameof(count)); } if (ReadState != ReadState.Interactive) { return Task.FromResult(0); } return Core(buffer, index, count); async Task<int> Core(byte[] buffer, int index, int count) { if (_state != State.InReadBinary) { // forward ReadBase64Chunk calls into the base (wrapped) reader if possible, i.e. if it can read binary and we // should not check characters if (base.CanReadBinaryContent && (!_checkCharacters)) { _readBinaryHelper = null; _state = State.InReadBinary; return await base.ReadElementContentAsBase64Async(buffer, index, count).ConfigureAwait(false); } // the wrapped reader cannot read chunks or we are on an element where we should check characters or ignore whitespace else { _readBinaryHelper = ReadContentAsBinaryHelper.CreateOrReset(_readBinaryHelper, this); } } else { // forward calls into wrapped reader if (_readBinaryHelper == null) { return await base.ReadElementContentAsBase64Async(buffer, index, count).ConfigureAwait(false); } } // turn off InReadBinary state in order to have a normal Read() behavior when called from readBinaryHelper _state = State.Interactive; // call to the helper int readCount = await _readBinaryHelper.ReadElementContentAsBase64Async(buffer, index, count).ConfigureAwait(false); // turn on InReadBinary in again and return _state = State.InReadBinary; return readCount; } } public override Task<int> ReadElementContentAsBinHexAsync(byte[] buffer, int index, int count) { ArgumentNullException.ThrowIfNull(buffer); if (index < 0 || (uint)count > buffer.Length - index) { throw new ArgumentOutOfRangeException(index < 0 ? nameof(index) : nameof(count)); } if (ReadState != ReadState.Interactive) { return Task.FromResult(0); } return Core(buffer, index, count); async Task<int> Core(byte[] buffer, int index, int count) { if (_state != State.InReadBinary) { // forward ReadBinHexChunk calls into the base (wrapped) reader if possible, i.e. if it can read chunks and we // should not check characters if (base.CanReadBinaryContent && (!_checkCharacters)) { _readBinaryHelper = null; _state = State.InReadBinary; return await base.ReadElementContentAsBinHexAsync(buffer, index, count).ConfigureAwait(false); } // the wrapped reader cannot read chunks or we are on an element where we should check characters or ignore whitespace else { _readBinaryHelper = ReadContentAsBinaryHelper.CreateOrReset(_readBinaryHelper, this); } } else { // forward calls into wrapped reader if (_readBinaryHelper == null) { return await base.ReadElementContentAsBinHexAsync(buffer, index, count).ConfigureAwait(false); } } // turn off InReadBinary state in order to have a normal Read() behavior when called from readBinaryHelper _state = State.Interactive; // call to the helper int readCount = await _readBinaryHelper.ReadElementContentAsBinHexAsync(buffer, index, count).ConfigureAwait(false); // turn on InReadBinary in again and return _state = State.InReadBinary; return readCount; } } } }