public IOperation GetOperation(byte[] buffer, int bufferLength, ref int currentBufferPosition, out int token)
        {
            //If a match couldn't fit in what's left of the buffer
            if (MinLength > bufferLength - currentBufferPosition)
            {
                token = -1;
                return(null);
            }

            int           i             = currentBufferPosition;
            OperationTrie current       = this;
            IOperation    operation     = null;
            int           index         = -1;
            int           offsetToMatch = 0;

            while (i < bufferLength)
            {
                if (!current._map.TryGetValue(buffer[i], out current))
                {   // the current byte doesn't match in the context of the current trie state
                    token = index;

                    if (index != -1)
                    {   // a full token match was encountered along the way - return its operation
                        currentBufferPosition = i - offsetToMatch;
                        return(operation);
                    }

                    // no token match
                    return(null);
                }

                if (current.HandlerTokenIndex != -1)
                {   // a full token was matched, note its operation
                    index         = current.HandlerTokenIndex;
                    operation     = current.End;
                    offsetToMatch = 0;
                }
                else
                {
                    ++offsetToMatch;
                }

                ++i;
            }

            if (index != -1)
            {   // matched to the end of the buffer
                currentBufferPosition = i;
            }

            // end of buffer, but a full token matched along the way - return its operation
            token = index;
            return(operation);
        }
        public static OperationTrie Create(IReadOnlyList <IOperation> modifiers)
        {
            OperationTrie root      = new OperationTrie();
            OperationTrie current   = root;
            int           length    = 0;
            int           minLength = 0;

            for (int i = 0; i < modifiers.Count; ++i)
            {
                for (int k = 0; k < modifiers[i].Tokens.Count; ++k)
                {
                    if (modifiers[i].Tokens[k] == null)
                    {
                        continue;
                    }

                    length = Math.Max(length, modifiers[i].Tokens[k].Length);

                    if (modifiers[i].Tokens[k].Length > 0)
                    {
                        minLength = minLength == 0
                            ? modifiers[i].Tokens[k].Length
                            : Math.Min(minLength, modifiers[i].Tokens[k].Length);
                    }

                    for (int j = 0; j < modifiers[i].Tokens[k].Length; ++j)
                    {
                        OperationTrie child;
                        if (!current._map.TryGetValue(modifiers[i].Tokens[k][j], out child))
                        {
                            child = new OperationTrie();
                            current._map[modifiers[i].Tokens[k][j]] = child;
                        }

                        current = child;
                    }

                    current.HandlerTokenIndex = k;
                    current.End = modifiers[i];
                    current     = root;
                }
            }

            root.MaxLength = length;
            root.MinLength = minLength;
            return(root);
        }
Пример #3
0
        public ProcessorState(Stream source, Stream target, int bufferSize, int flushThreshold, IEngineConfig config, IReadOnlyList <IOperationProvider> operationProviders)
        {
            bool sizedToStream = false;

            //Buffer has to be at least as large as the largest BOM we could expect
            if (bufferSize < 4)
            {
                bufferSize = 4;
            }
            else
            {
                try
                {
                    if (source.Length < bufferSize)
                    {
                        sizedToStream = true;
                        bufferSize    = (int)source.Length;
                    }
                }
                catch
                {
                    //The stream may not support getting the length property (in NetworkStream for instance, which throw a NotSupportedException), suppress any errors in
                    //  accessing the property and continue with the specified buffer size
                }
            }

            _source             = source;
            _target             = target;
            Config              = config;
            _flushThreshold     = flushThreshold;
            CurrentBuffer       = new byte[bufferSize];
            CurrentBufferLength = source.Read(CurrentBuffer, 0, CurrentBuffer.Length);

            byte[]   bom;
            Encoding encoding = EncodingUtil.Detect(CurrentBuffer, CurrentBufferLength, out bom);

            Encoding = encoding;
            CurrentBufferPosition = bom.Length;
            target.Write(bom, 0, bom.Length);

            Dictionary <Encoding, OperationTrie> byEncoding;

            if (!TrieLookup.TryGetValue(operationProviders, out byEncoding))
            {
                TrieLookup[operationProviders] = byEncoding = new Dictionary <Encoding, OperationTrie>();
            }

            if (!byEncoding.TryGetValue(encoding, out _trie))
            {
                List <IOperation> operations = new List <IOperation>(operationProviders.Count);

                for (int i = 0; i < operationProviders.Count; ++i)
                {
                    IOperation op = operationProviders[i].GetOperation(encoding, this);
                    if (op != null)
                    {
                        operations.Add(op);
                    }
                }

                byEncoding[encoding] = _trie = OperationTrie.Create(operations);
            }

            if (bufferSize < _trie.MaxLength && !sizedToStream)
            {
                byte[] tmp = new byte[_trie.MaxLength];
                Buffer.BlockCopy(CurrentBuffer, CurrentBufferPosition, tmp, 0, CurrentBufferLength - CurrentBufferPosition);
                int nRead = _source.Read(tmp, CurrentBufferLength - CurrentBufferPosition, tmp.Length - CurrentBufferLength);
                CurrentBuffer         = tmp;
                CurrentBufferLength  += nRead;
                CurrentBufferPosition = 0;
            }
        }