mirror of
https://github.com/BeyondDimension/SteamTools.git
synced 2026-10-18 22:50:50 +08:00
137 lines
5.2 KiB
C#
137 lines
5.2 KiB
C#
using NUnit.Framework;
|
|
using System.Text;
|
|
|
|
namespace System.Application;
|
|
|
|
[TestFixture]
|
|
public class BytesTest
|
|
{
|
|
[Test]
|
|
public async Task ScriptInject()
|
|
{
|
|
//var htmlString = await new HttpClient().GetStringAsync("https://store.steampowered.com/");
|
|
const string htmlString = "<html><head></head><body><img src=\"https://store.st.dl.eccdnx.com/public/shared/images/header/logo_steam.svg?t=962016\" width=\"176\" height=\"44\"><div></div></body></html>";
|
|
|
|
var encoding = Encoding.UTF8;
|
|
var buffer_ = encoding.GetBytes(htmlString);
|
|
|
|
if (FindScriptInjectInsertPosition(buffer_, encoding, out var buffer, out var position))
|
|
{
|
|
using var bodyCoreWriter = new MemoryStream();
|
|
await bodyCoreWriter.WriteAsync(buffer[..position]);
|
|
const string scriptXmlStart = "<script type=\"text/javascript\" src=\"https://local.steampp.net/";
|
|
const string scriptXmlEnd = "\"></script>";
|
|
var scriptXmlStartBytes = encoding.GetBytes(scriptXmlStart);
|
|
var scriptXmlEndBytes = encoding.GetBytes(scriptXmlEnd);
|
|
|
|
await bodyCoreWriter.WriteAsync(scriptXmlStartBytes);
|
|
await bodyCoreWriter.WriteAsync(encoding.GetBytes("2"));
|
|
await bodyCoreWriter.WriteAsync(scriptXmlEndBytes);
|
|
|
|
await bodyCoreWriter.WriteAsync(buffer[position..]);
|
|
|
|
var data = bodyCoreWriter.ToArray();
|
|
var htmlString2 = encoding.GetString(data);
|
|
TestContext.WriteLine(htmlString2);
|
|
}
|
|
else
|
|
{
|
|
throw new Exception("FindScriptInjectInsertPosition fail.");
|
|
}
|
|
}
|
|
|
|
static readonly object marksLock = new();
|
|
static readonly Dictionary<int, (byte[] mark_start, byte[] mark_end)> marksDict = new();
|
|
|
|
static (byte[] mark_start, byte[] mark_end) GetMarks(Encoding encoding)
|
|
{
|
|
var codePage = encoding.CodePage;
|
|
if (marksDict.ContainsKey(codePage)) return marksDict[codePage];
|
|
lock (marksLock)
|
|
{
|
|
var mark_start = encoding.GetBytes("</");
|
|
var mark_end = encoding.GetBytes(">");
|
|
var value = (mark_start, mark_end);
|
|
marksDict.Add(codePage, value);
|
|
return value;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 查找脚本注入位置
|
|
/// </summary>
|
|
/// <param name="buffer_">Response.Body ByteArray</param>
|
|
/// <param name="encoding">Response.Body Encoding</param>
|
|
/// <param name="buffer">Response.Body Byte[]</param>
|
|
/// <param name="insertPosition">Insert Script Xml Position</param>
|
|
/// <returns></returns>
|
|
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
|
static bool FindScriptInjectInsertPosition(byte[] buffer_, Encoding encoding, out ReadOnlyMemory<byte> buffer, out int insertPosition)
|
|
{
|
|
buffer = buffer_.AsMemory();
|
|
|
|
// 匹配 </...> 60 47 ... 62
|
|
(var mark_start, var mark_end) = GetMarks(encoding);
|
|
if (mark_start.Length <= 0 || mark_end.Length <= 0) goto notfound;
|
|
|
|
int index_name_end = 0;
|
|
int match_mark_end_index = 0;
|
|
int match_mark_start_index = 0;
|
|
|
|
for (int i = buffer_.Length - 1; i >= 0; i--) // 倒序匹配,对应之前的 LastIndexOf(string
|
|
{
|
|
var item = buffer_[i];
|
|
if (index_name_end == 0)
|
|
{
|
|
var index = mark_end.Length - 1 - match_mark_end_index;
|
|
if (index >= 0 && index < mark_end.Length && item == mark_end[index]) // 匹配末尾
|
|
{
|
|
if (item == mark_end[index])
|
|
{
|
|
match_mark_end_index++;
|
|
if (match_mark_end_index >= mark_end.Length)
|
|
{
|
|
if (index_name_end == 0)
|
|
{
|
|
index_name_end = i;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
var index = mark_start.Length - 1 - match_mark_start_index;
|
|
if (index >= 0 && index < mark_start.Length && item == mark_start[index]) // 匹配开头
|
|
{
|
|
match_mark_start_index++;
|
|
if (match_mark_start_index >= mark_start.Length)
|
|
{
|
|
var index_name_start = i + mark_start.Length;
|
|
var name = encoding.GetString(buffer.Span[index_name_start..index_name_end]);
|
|
if (name.Equals("body", StringComparison.OrdinalIgnoreCase) ||
|
|
name.Equals("head", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
insertPosition = index_name_start - mark_start.Length;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
goto reset;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
continue;
|
|
|
|
|
|
reset: index_name_end = match_mark_end_index = match_mark_start_index = 0;
|
|
}
|
|
|
|
notfound: insertPosition = -1;
|
|
return false;
|
|
}
|
|
}
|