Terraria v1.4.4.9
Terraria source code documentation
Loading...
Searching...
No Matches
WebSocketDeflater.cs
Go to the documentation of this file.
3
5
6internal sealed class WebSocketDeflater : IDisposable
7{
8 private readonly int _windowBits;
9
11
12 private readonly bool _persisted;
13
14 private byte[] _buffer;
15
16 internal WebSocketDeflater(int windowBits, bool persisted)
17 {
18 _windowBits = -windowBits;
19 _persisted = persisted;
20 }
21
22 public void Dispose()
23 {
24 if (_stream != null)
25 {
26 _stream.Dispose();
27 _stream = null;
28 }
29 }
30
31 public void ReleaseBuffer()
32 {
33 byte[] buffer = _buffer;
34 if (buffer != null)
35 {
36 _buffer = null;
38 }
39 }
40
41 public ReadOnlySpan<byte> Deflate(ReadOnlySpan<byte> payload, bool endOfMessage)
42 {
43 _buffer = ArrayPool<byte>.Shared.Rent(Math.Max(payload.Length, 4096));
44 int num = 0;
45 while (true)
46 {
47 DeflatePrivate(payload, _buffer.AsSpan(num), endOfMessage, out var consumed, out var written, out var needsMoreOutput);
48 num += written;
49 if (!needsMoreOutput)
50 {
51 break;
52 }
53 payload = payload.Slice(consumed);
54 byte[] array = ArrayPool<byte>.Shared.Rent((int)((double)_buffer.Length * 1.3));
55 _buffer.AsSpan(0, num).CopyTo(array);
56 byte[] buffer = _buffer;
57 _buffer = array;
59 }
60 return new ReadOnlySpan<byte>(_buffer, 0, num);
61 }
62
63 private void DeflatePrivate(ReadOnlySpan<byte> payload, Span<byte> output, bool endOfMessage, out int consumed, out int written, out bool needsMoreOutput)
64 {
65 if (_stream == null)
66 {
68 }
69 if (payload.Length == 0)
70 {
71 consumed = 0;
72 written = 0;
73 }
74 else
75 {
76 UnsafeDeflate(payload, output, out consumed, out written, out needsMoreOutput);
77 if (needsMoreOutput)
78 {
79 return;
80 }
81 }
82 written += UnsafeFlush(output.Slice(written), out needsMoreOutput);
83 if (!needsMoreOutput)
84 {
85 if (endOfMessage)
86 {
87 written -= 4;
88 }
89 if (endOfMessage && !_persisted)
90 {
91 _stream.Dispose();
92 _stream = null;
93 }
94 }
95 }
96
97 private unsafe void UnsafeDeflate(ReadOnlySpan<byte> input, Span<byte> output, out int consumed, out int written, out bool needsMoreBuffer)
98 {
99 fixed (byte* ptr = input)
100 {
101 fixed (byte* ptr2 = output)
102 {
103 _stream.NextIn = (IntPtr)ptr;
104 _stream.AvailIn = (uint)input.Length;
105 _stream.NextOut = (IntPtr)ptr2;
106 _stream.AvailOut = (uint)output.Length;
108 consumed = input.Length - (int)_stream.AvailIn;
109 written = output.Length - (int)_stream.AvailOut;
110 needsMoreBuffer = errorCode == ZLibNative.ErrorCode.BufError || _stream.AvailIn != 0;
111 }
112 }
113 }
114
115 private unsafe int UnsafeFlush(Span<byte> output, out bool needsMoreBuffer)
116 {
117 fixed (byte* ptr = output)
118 {
119 _stream.NextIn = IntPtr.Zero;
120 _stream.AvailIn = 0u;
121 _stream.NextOut = (IntPtr)ptr;
122 _stream.AvailOut = (uint)output.Length;
124 needsMoreBuffer = _stream.AvailOut < 6;
125 if (!needsMoreBuffer)
126 {
127 errorCode = Deflate(_stream, ZLibNative.FlushCode.SyncFlush);
128 }
129 return output.Length - (int)_stream.AvailOut;
130 }
131 }
132
134 {
135 ZLibNative.ErrorCode errorCode = stream.Deflate(flushCode);
136 string text;
137 switch (errorCode)
138 {
139 case ZLibNative.ErrorCode.BufError:
140 case ZLibNative.ErrorCode.Ok:
141 case ZLibNative.ErrorCode.StreamEnd:
142 return errorCode;
143 default:
144 text = string.Format(System.SR.ZLibErrorUnexpected, (int)errorCode);
145 break;
146 case ZLibNative.ErrorCode.StreamError:
148 break;
149 }
150 string message = text;
151 throw new WebSocketException(message);
152 }
153
155 {
156 ZLibNative.ErrorCode errorCode;
157 ZLibNative.ZLibStreamHandle zLibStreamHandle;
158 try
159 {
160 errorCode = ZLibNative.CreateZLibStreamForDeflate(out zLibStreamHandle, ZLibNative.CompressionLevel.DefaultCompression, _windowBits, 8, ZLibNative.CompressionStrategy.DefaultStrategy);
161 }
162 catch (Exception innerException)
163 {
164 throw new WebSocketException(System.SR.ZLibErrorDLLLoadError, innerException);
165 }
166 if (errorCode == ZLibNative.ErrorCode.Ok)
167 {
168 return zLibStreamHandle;
169 }
170 zLibStreamHandle.Dispose();
171 string message = ((errorCode == ZLibNative.ErrorCode.MemError) ? System.SR.ZLibErrorNotEnoughMemory : string.Format(System.SR.ZLibErrorUnexpected, (int)errorCode));
172 throw new WebSocketException(message);
173 }
174}
static ArrayPool< T > Shared
Definition ArrayPool.cs:7
static ErrorCode CreateZLibStreamForDeflate(out ZLibStreamHandle zLibStreamHandle, CompressionLevel level, int windowBits, int memLevel, CompressionStrategy strategy)
static byte Max(byte val1, byte val2)
Definition Math.cs:738
ReadOnlySpan< byte > Deflate(ReadOnlySpan< byte > payload, bool endOfMessage)
unsafe void UnsafeDeflate(ReadOnlySpan< byte > input, Span< byte > output, out int consumed, out int written, out bool needsMoreBuffer)
void DeflatePrivate(ReadOnlySpan< byte > payload, Span< byte > output, bool endOfMessage, out int consumed, out int written, out bool needsMoreOutput)
unsafe int UnsafeFlush(Span< byte > output, out bool needsMoreBuffer)
static ZLibNative.ErrorCode Deflate(ZLibNative.ZLibStreamHandle stream, ZLibNative.FlushCode flushCode)
static string ZLibErrorNotEnoughMemory
Definition SR.cs:46
static string ZLibErrorDLLLoadError
Definition SR.cs:40
static string ZLibErrorInconsistentStream
Definition SR.cs:42
static string ZLibErrorUnexpected
Definition SR.cs:50
Definition SR.cs:7
static readonly IntPtr Zero
Definition IntPtr.cs:18
ReadOnlySpan< T > Slice(int start)
Span< T > Slice(int start)
Definition Span.cs:271
int Length
Definition Span.cs:70