/// <exception cref="System.IO.IOException"/>
        public override int Read(char[] cbuf, int off, int len)
        {
            var readAhead       = 0;
            var read            = 0;
            var pos             = off;
            var readAheadBuffer = new char[BufferSize];
            var available       = true;

            while (available && read < len)
            {
                available = base.Read(readAheadBuffer, readAhead, 1) == 1;
                if (available)
                {
                    var c = ProcessChar(readAheadBuffer[readAhead]);
                    if (_state == StateStart)
                    {
                        // replace control chars with space
                        if (Utils.IsControlChar(c))
                        {
                            c = ' ';
                        }
                        cbuf[pos++] = c;
                        readAhead   = 0;
                        read++;
                    }
                    else
                    {
                        if (_state == StateError)
                        {
                            Unread(readAheadBuffer, 0, readAhead + 1);
                            readAhead = 0;
                        }
                        else
                        {
                            readAhead++;
                        }
                    }
                }
                else
                {
                    if (readAhead > 0)
                    {
                        // handles case when file ends within excaped sequence
                        Unread(readAheadBuffer, 0, readAhead);
                        _state    = StateError;
                        readAhead = 0;
                        available = true;
                    }
                }
            }
            return(read > 0 || available ? read : -1);
        }
示例#2
0
        /// <summary>Processes numeric escaped chars to find out if they are a control character.</summary>
        /// <param name="ch">a char</param>
        /// <returns>Returns the char directly or as replacement for the escaped sequence.</returns>
        private char ProcessChar(char ch)
        {
            switch (_state)
            {
                case StateStart:
                {
                    if (ch == '&')
                    {
                        _state = StateAmp;
                    }
                    return ch;
                }

                case StateAmp:
                {
                    _state = ch == '#' ? StateHash : StateError;
                    return ch;
                }

                case StateHash:
                {
                    if (ch == 'x')
                    {
                        _control = 0;
                        _digits = 0;
                        _state = StateHex;
                    }
                    else
                    {
                        if ('0' <= ch && ch <= '9')
                        {
                            _control = ch - '0';
                            _digits = 1;
                            _state = StateDig1;
                        }
                        else
                        {
                            _state = StateError;
                        }
                    }
                    return ch;
                }

                case StateDig1:
                {
                    if ('0' <= ch && ch <= '9')
                    {
                        _control = _control*10 + (ch - '0');
                        _digits++;
                        _state = _digits <= 5 ? StateDig1 : StateError;
                    }
                    else
                    {
                        // sequence too long
                        if (ch == ';' && Utils.IsControlChar((char)_control))
                        {
                            _state = StateStart;
                            return (char)_control;
                        }
                        _state = StateError;
                    }
                    return ch;
                }

                case StateHex:
                {
                    if (('0' <= ch && ch <= '9') || ('a' <= ch && ch <= 'f') || ('A' <= ch && ch <= 'F'))
                    {
                        _control = _control*16 + Convert.ToInt32(ch.ToString(), fromBase: 16);
                        _digits++;
                        _state = _digits <= 4 ? StateHex : StateError;
                    }
                    else
                    {
                        // sequence too long
                        if (ch == ';' && Utils.IsControlChar((char)_control))
                        {
                            _state = StateStart;
                            return (char)_control;
                        }
                        _state = StateError;
                    }
                    return ch;
                }

                case StateError:
                {
                    _state = StateStart;
                    return ch;
                }

                default:
                {
                    // not reachable
                    return ch;
                }
            }
        }