-
Notifications
You must be signed in to change notification settings - Fork 1
/
Shared.cs
122 lines (103 loc) · 3.54 KB
/
Shared.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
namespace LC6464.Base16384;
/// <summary>
/// Base16384 编解码器。
/// </summary>
public static partial class Base16384 {
private static byte IsNextEnd(Stream stream) {
var ch = stream.ReadByte();
if (ch == -1) {
return 0;
}
if (ch == '=') {
return (byte)stream.ReadByte();
}
stream.Position--;
return 0;
}
private static void EncodeLengthInternal(long dataLength, out long outLength, out long offset) {
outLength = dataLength / 7 * 8;
offset = dataLength % 7;
switch (offset) { // 算上偏移标志字符占用的2字节
case 0: break;
case 1: outLength += 4; break;
case 2:
case 3: outLength += 6; break;
case 4:
case 5: outLength += 8; break;
case 6: outLength += 10; break;
default: break; // outLength += 0;
}
}
/// <summary>
/// 原始数据缓冲区长度。
/// </summary>
public const int Buffer0Length = 8192 * 1024 / 7 * 7;
/// <summary>
/// 编码后数据缓冲区长度。
/// </summary>
public const int Buffer1Length = 8192 * 1024 / 8 * 8;
/// <summary>
/// UTF-16 BE 编码的 BOM,应在文件头部出现。
/// </summary>
public static ReadOnlySpan<byte> Utf16BEPreamble => new byte[] { 0xFE, 0xFF };
/// <summary>
/// UTF-16 LE 编码的 BOM,应在文件头部出现。
/// </summary>
public static ReadOnlySpan<byte> Utf16LEPreamble => new byte[] { 0xFF, 0xFE };
/// <summary>
/// UTF-8 with BOM 编码的 BOM,应在文件头部出现。
/// </summary>
public static ReadOnlySpan<byte> Utf8Preamble => new byte[] { 0xEF, 0xBB, 0xBF };
/// <summary>
/// 计算编码指针需要的长度。
/// </summary>
/// <param name="dataLength">数据长度</param>
/// <returns>编码指针需要的长度</returns>
public static long EncodeLength(long dataLength) {
EncodeLengthInternal(dataLength, out var outLength, out _);
return outLength + 8 + 16; // 冗余的8B用于可能的结尾的覆盖,再加上16B备用
}
/// <summary>
/// 计算解码指针需要的长度。
/// </summary>
/// <param name="dataLength">数据长度</param>
/// <param name="offset">偏移量(默认为0,作用未知,可参见 GitHub: fumiama/base16384。)</param>
/// <returns>解码指针需要的长度</returns>
public static long DecodeLength(long dataLength, long offset = 0) {
var outLength = dataLength;
switch (offset) { // 算上偏移标志字符占用的2字节
case 0: break;
case 1: outLength -= 4; break;
case 2:
case 3: outLength -= 6; break;
case 4:
case 5: outLength -= 8; break;
case 6: outLength -= 10; break;
default: break; // outLength += 0;
}
return (outLength / 8 * 7) + offset + 1 + 16; // 多出1字节用于循环覆盖,再加上16B备用
}
/// <summary>
/// 将 <paramref name="data"/>(可能在非托管内存中)复制到托管内存中。
/// </summary>
/// <typeparam name="T"><paramref name="data"/> 的类型</typeparam>
/// <param name="data">要复制的数据</param>
/// <returns>复制结果</returns>
public static ReadOnlySpan<T> CopyToManagedMemory<T>(this ReadOnlySpan<T> data) {
Span<T> result = new(new T[data.Length]);
data.CopyTo(result);
return result;
}
/// <summary>
/// 将非托管内存中的 <paramref name="data"/> 移动到托管内存中。
/// </summary>
/// <param name="data">要移动的数据</param>
/// <returns>移动结果</returns>
public static unsafe ReadOnlySpan<byte> MoveFromHGlobalToManagedMemory(this ReadOnlySpan<byte> data) {
var result = data.CopyToManagedMemory();
fixed (byte* ptr = data) {
Marshal.FreeHGlobal((nint)ptr);
}
return result;
}
}