// Copyright © 2016 The CefSharp Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace CefSharp.Example.Filters
{
//NOTE: You need to make sure that your queries are in chronological order since the stream doesn't rewind
public class FindReplaceMultiResponseFilter : IResponseFilter
{
private static readonly Encoding encoding = Encoding.UTF8;
///
/// The portion of the find string that is currently matching.
///
private int findMatchOffset;
///
/// Overflow from the output buffer.
///
private readonly List overflow = new List();
///
/// Number of times the the string was found/replaced.
///
private int replaceCount;
private List> dictionary;
public FindReplaceMultiResponseFilter(List> dictionary)
{
this.dictionary = dictionary;
}
bool IResponseFilter.InitFilter()
{
return true;
}
FilterStatus IResponseFilter.Filter(Stream dataIn, out long dataInRead, Stream dataOut, out long dataOutWritten)
{
// All data will be read.
dataInRead = dataIn == null ? 0 : dataIn.Length;
dataOutWritten = 0;
// Write overflow then reset
if (overflow.Count > 0)
{
// Write the overflow from last time.
WriteOverflow(dataOut, ref dataOutWritten);
}
// Evaluate each character in the input buffer. Track how many characters in
// a row match findString. If findString is completely matched then write
// replacement. Otherwise, write the input characters as-is.
for (var i = 0; i < dataInRead; ++i)
{
var readByte = (byte)dataIn.ReadByte();
var charForComparison = Convert.ToChar(readByte);
if (replaceCount < dictionary.Count)
{
var replace = dictionary.ElementAt(replaceCount);
if (charForComparison == replace.Key[findMatchOffset])
{
//We have a match, increment the counter
findMatchOffset++;
// If all characters match the string specified
if (findMatchOffset == replace.Key.Length)
{
// Complete match of the find string. Write the replace string.
WriteString(replace.Value, replace.Value.Length, dataOut, ref dataOutWritten);
// Start over looking for a match.
findMatchOffset = 0;
replaceCount++;
}
continue;
}
// Character did not match the find string.
if (findMatchOffset > 0)
{
// Write the portion of the find string that has matched so far.
WriteString(replace.Key, findMatchOffset, dataOut, ref dataOutWritten);
// Start over looking for a match.
findMatchOffset = 0;
}
}
// Write the current character.
WriteSingleByte(readByte, dataOut, ref dataOutWritten);
}
if (overflow.Count > 0)
{
//If we end up with overflow data then we'll need to return NeedMoreData
// On the next pass the data will be written, then the next batch will be processed.
return FilterStatus.NeedMoreData;
}
// If a match is currently in-progress we need more data. Otherwise, we're
// done.
return findMatchOffset > 0 ? FilterStatus.NeedMoreData : FilterStatus.Done;
}
private void WriteOverflow(Stream dataOut, ref long dataOutWritten)
{
// Number of bytes remaining in the output buffer.
var remainingSpace = dataOut.Length - dataOutWritten;
// Maximum number of bytes we can write into the output buffer.
var maxWrite = Math.Min(overflow.Count, remainingSpace);
// Write the maximum portion that fits in the output buffer.
if (maxWrite > 0)
{
dataOut.Write(overflow.ToArray(), 0, (int)maxWrite);
dataOutWritten += maxWrite;
}
if (maxWrite < overflow.Count)
{
// Need to write more bytes than will fit in the output buffer.
// Remove the bytes that were written already
overflow.RemoveRange(0, (int)(maxWrite - 1));
}
else
{
overflow.Clear();
}
}
private void WriteString(string str, int stringSize, Stream dataOut, ref long dataOutWritten)
{
// Number of bytes remaining in the output buffer.
var remainingSpace = dataOut.Length - dataOutWritten;
// Maximum number of bytes we can write into the output buffer.
var maxWrite = Math.Min(stringSize, remainingSpace);
// Write the maximum portion that fits in the output buffer.
if (maxWrite > 0)
{
var bytes = encoding.GetBytes(str);
dataOut.Write(bytes, 0, (int)maxWrite);
dataOutWritten += maxWrite;
}
if (maxWrite < stringSize)
{
// Need to write more bytes than will fit in the output buffer. Store the
// remainder in the overflow buffer.
overflow.AddRange(encoding.GetBytes(str.Substring((int)maxWrite, (int)(stringSize - maxWrite))));
}
}
private void WriteSingleByte(byte data, Stream dataOut, ref long dataOutWritten)
{
// Number of bytes remaining in the output buffer.
var remainingSpace = dataOut.Length - dataOutWritten;
// Write the byte to the buffer or add it to the overflow
if (remainingSpace > 0)
{
dataOut.WriteByte(data);
dataOutWritten += 1;
}
else
{
// Need to write more bytes than will fit in the output buffer. Store the
// remainder in the overflow buffer.
overflow.Add(data);
}
}
void IDisposable.Dispose()
{
}
}
}