public ProcessorState(Stream source, Stream target, int bufferSize, int flushThreshold, IEngineConfig config, IReadOnlyList <IOperationProvider> operationProviders) { if (source == null) { throw new ArgumentNullException(nameof(source)); } if (target == null) { throw new ArgumentNullException(nameof(target)); } if (config == null) { throw new ArgumentNullException(nameof(config)); } if (operationProviders == null) { throw new ArgumentNullException(nameof(operationProviders)); } if (source.CanSeek) { try { if (source.Length < bufferSize) { 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 } } //Buffer has to be at least as large as the largest BOM we could expect else if (bufferSize < 4) { bufferSize = 4; } _source = source; _target = target; Config = config; _flushThreshold = flushThreshold; CurrentBuffer = new byte[bufferSize]; CurrentBufferLength = ReadExactBytes(source, CurrentBuffer, 0, CurrentBuffer.Length); Encoding encoding = EncodingUtil.Detect(CurrentBuffer, CurrentBufferLength, out byte[] bom); EncodingConfig = new EncodingConfig(Config, encoding); _bomSize = bom.Length; CurrentBufferPosition = _bomSize; CurrentSequenceNumber = _bomSize; target.Write(bom, 0, _bomSize); bool explicitOnConfigurationRequired = false; Dictionary <Encoding, Trie <OperationTerminal> > byEncoding = TrieLookup.GetOrAdd(operationProviders, x => new Dictionary <Encoding, Trie <OperationTerminal> >()); List <string> turnOnByDefault = OperationsToExplicitlySetOnByDefault.GetOrAdd(operationProviders, x => { explicitOnConfigurationRequired = true; return(new List <string>()); }); if (!byEncoding.TryGetValue(encoding, out Trie <OperationTerminal> trie)) { trie = new Trie <OperationTerminal>(); for (int i = 0; i < operationProviders.Count; ++i) { IOperation op = operationProviders[i].GetOperation(encoding, this); if (op != null) { for (int j = 0; j < op.Tokens.Count; ++j) { if (op.Tokens[j] != null) { trie.AddPath(op.Tokens[j].Value, new OperationTerminal(op, j, op.Tokens[j].Length, op.Tokens[j].Start, op.Tokens[j].End)); } } if (explicitOnConfigurationRequired && op.IsInitialStateOn && !string.IsNullOrEmpty(op.Id)) { turnOnByDefault.Add(op.Id); } } } byEncoding[encoding] = trie; } foreach (string state in turnOnByDefault) { config.Flags[state] = true; } _trie = new TrieEvaluator <OperationTerminal>(trie); if (bufferSize < _trie.MaxLength + 1) { byte[] tmp = new byte[_trie.MaxLength + 1]; Buffer.BlockCopy(CurrentBuffer, CurrentBufferPosition, tmp, 0, CurrentBufferLength - CurrentBufferPosition); int nRead = ReadExactBytes(_source, tmp, CurrentBufferLength - CurrentBufferPosition, tmp.Length - CurrentBufferLength); CurrentBuffer = tmp; CurrentBufferLength += nRead - _bomSize; CurrentBufferPosition = 0; CurrentSequenceNumber = 0; } }