gg.easy.airship 0.1.2136 → 0.1.2137
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Editor/Artifacts/AirshipLocalArtifactDatabase.cs +5 -1
- package/Editor/TypescriptServices/Compiler/TypescriptCompilationService.cs +27 -3
- package/Editor/TypescriptServices/TypescriptServices.cs +1 -1
- package/Runtime/Code/Luau/AirshipScript.cs +2 -0
- package/Runtime/Code/Network/Simulation/AirshipSimulationManager.cs +13 -15
- package/Runtime/Code/Network/StateSystem/AirshipNetworkedStateManager.cs +5 -4
- package/Runtime/Code/VoxelWorld/Airship.VoxelWorld.asmdef +2 -1
- package/Runtime/Code/VoxelWorld/VoxelCompressUtil.cs +26 -3
- package/Runtime/Code/VoxelWorld/VoxelWorldChunk.cs +1 -1
- package/Runtime/Code/VoxelWorld/WorldSaveFile.cs +8 -6
- package/Runtime/Code/Zstd/Zstd.cs +125 -47
- package/Runtime/Code/Zstd/ZstdCompressStream.cs +147 -0
- package/Runtime/Code/Zstd/ZstdCompressStream.cs.meta +3 -0
- package/Runtime/Code/Zstd/ZstdDecompressStream.cs +196 -0
- package/Runtime/Code/Zstd/ZstdDecompressStream.cs.meta +3 -0
- package/Runtime/Code/Zstd/ZstdNative.cs +5 -5
- package/Runtime/Plugins/Android/libLuauPlugin.so +0 -0
- package/Runtime/Plugins/Linux/libLuauPlugin.so +0 -0
- package/Runtime/Plugins/Mac/LuauPlugin.bundle/Contents/MacOS/LuauPlugin +0 -0
- package/Runtime/Plugins/Windows/x64/LuauPlugin.dll +0 -0
- package/Runtime/Plugins/Windows/x64/LuauPlugin.pdb +0 -0
- package/Runtime/Plugins/iOS/LuauPluginIos.a +0 -0
- package/package.json +1 -1
|
@@ -150,7 +150,11 @@ namespace Airship.Editor {
|
|
|
150
150
|
/// Will try to get the script asset data associated with the specified script (if applicable)
|
|
151
151
|
/// </summary>
|
|
152
152
|
internal bool TryGetScriptAssetData(AirshipScript script, out ComponentScriptAssetData assetData) {
|
|
153
|
-
|
|
153
|
+
return TryGetScriptAssetDataFromPath(script.assetPath, out assetData);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
internal bool TryGetScriptAssetDataFromPath(string path, out ComponentScriptAssetData assetData) {
|
|
157
|
+
var item = scripts.FirstOrDefault(f => f.script == path);
|
|
154
158
|
if (item != null) {
|
|
155
159
|
assetData = item;
|
|
156
160
|
return true;
|
|
@@ -225,18 +225,42 @@ using Object = UnityEngine.Object;
|
|
|
225
225
|
return;
|
|
226
226
|
}
|
|
227
227
|
|
|
228
|
+
var artifacts = AirshipLocalArtifactDatabase.instance;
|
|
229
|
+
var modifiedDatabase = false;
|
|
230
|
+
|
|
228
231
|
try {
|
|
229
232
|
AssetDatabase.StartAssetEditing();
|
|
230
233
|
var compileFileList = CompiledFileQueue.ToArray();
|
|
234
|
+
|
|
231
235
|
foreach (var file in compileFileList) {
|
|
232
|
-
|
|
233
|
-
|
|
236
|
+
var outFileHash = TypescriptProjectsService.Project.GetOutputFileHash(file);
|
|
237
|
+
|
|
238
|
+
if (artifacts.TryGetScriptAssetDataFromPath(PosixPath.ToPosix(file), out var data)) {
|
|
239
|
+
if (outFileHash != data.metadata.compiledHash) {
|
|
240
|
+
AssetDatabase.ImportAsset(file, ImportAssetOptions.Default);
|
|
241
|
+
data.metadata.compiledHash = outFileHash;
|
|
242
|
+
modifiedDatabase = true;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
var scriptData = artifacts.GetOrCreateScriptAssetData(AssetDatabase.LoadAssetAtPath<AirshipScript>(file));
|
|
247
|
+
scriptData.metadata = new TypescriptCompilerMetadata() {
|
|
248
|
+
compiledHash = outFileHash
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
AssetDatabase.ImportAsset(file, ImportAssetOptions.Default);
|
|
252
|
+
modifiedDatabase = true;
|
|
253
|
+
}
|
|
234
254
|
}
|
|
255
|
+
|
|
235
256
|
AssetDatabase.Refresh();
|
|
236
257
|
} catch (Exception ex) {
|
|
237
|
-
Debug.
|
|
258
|
+
Debug.LogException(ex);
|
|
238
259
|
} finally {
|
|
239
260
|
AssetDatabase.StopAssetEditing();
|
|
261
|
+
if (modifiedDatabase) {
|
|
262
|
+
artifacts.Modify();
|
|
263
|
+
}
|
|
240
264
|
}
|
|
241
265
|
|
|
242
266
|
EditorApplication.update -= ReimportCompiledFiles;
|
|
@@ -65,7 +65,7 @@ namespace Airship.Editor {
|
|
|
65
65
|
return;
|
|
66
66
|
#endif
|
|
67
67
|
// On project load we'll force a full compile to try and get all the refs up to date
|
|
68
|
-
if (!SessionState.GetBool("TypescriptInitialBoot", false)) {
|
|
68
|
+
if (!SessionState.GetBool("TypescriptInitialBoot", false) && IsValidEditor) {
|
|
69
69
|
SessionState.SetBool("TypescriptInitialBoot", true);
|
|
70
70
|
TypescriptCompilationService.BuildTypescript(TypeScriptCompileFlags.FullClean | TypeScriptCompileFlags.Setup | TypeScriptCompileFlags.DisplayProgressBar);
|
|
71
71
|
}
|
|
@@ -102,12 +102,10 @@ namespace Code.Network.Simulation
|
|
|
102
102
|
*/
|
|
103
103
|
public event Action<int, double, double> OnLagCompensationCheck;
|
|
104
104
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
public event Action<double, bool> OnPerformTick;
|
|
110
|
-
|
|
105
|
+
/// <summary>
|
|
106
|
+
/// This action tells all watching components that they need to perform a tick.
|
|
107
|
+
/// A Physics.Simulate() call will be made after PerformTick completes.
|
|
108
|
+
/// </summary>
|
|
111
109
|
public event Action<object, object> OnTick;
|
|
112
110
|
|
|
113
111
|
/**
|
|
@@ -184,7 +182,6 @@ namespace Code.Network.Simulation
|
|
|
184
182
|
if (resimBackTo != time) this.PerformResimulation(resimBackTo);
|
|
185
183
|
|
|
186
184
|
// Perform the standard tick behavior
|
|
187
|
-
OnPerformTick?.Invoke(time, false);
|
|
188
185
|
OnTick?.Invoke(time, false);
|
|
189
186
|
// Debug.Log("Simulate call. Main Tick: " + NetworkTime.time);
|
|
190
187
|
Physics.Simulate(Time.fixedDeltaTime);
|
|
@@ -310,13 +307,14 @@ namespace Code.Network.Simulation
|
|
|
310
307
|
this.ScheduleResimulation((resim => resim(time)));
|
|
311
308
|
}
|
|
312
309
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
310
|
+
/// <summary>
|
|
311
|
+
/// Requests a simulation based on the provided time. Requesting a simulation will roll back the physics
|
|
312
|
+
/// world to the snapshot just before or at the base time provided. Calling the returned tick function
|
|
313
|
+
/// will advance the simulation and re-simulate the calls to <see cref="OnTick"/>, Physics.Simulate,
|
|
314
|
+
/// and <see cref="OnCaptureSnapshot"/>
|
|
315
|
+
///
|
|
316
|
+
/// This function is used internally to implement the scheduled resimulations.
|
|
317
|
+
/// </summary>
|
|
320
318
|
private void PerformResimulation(double baseTime)
|
|
321
319
|
{
|
|
322
320
|
Debug.Log($"T:{Time.unscaledTimeAsDouble} Resimulating from {baseTime}");
|
|
@@ -343,7 +341,7 @@ namespace Code.Network.Simulation
|
|
|
343
341
|
|
|
344
342
|
while (tickIndex < this.tickTimes.Count)
|
|
345
343
|
{
|
|
346
|
-
|
|
344
|
+
OnTick?.Invoke(this.tickTimes[tickIndex], true);
|
|
347
345
|
// Debug.Log("Simulate call. Replay Tick: " + this.tickTimes[tickIndex]);
|
|
348
346
|
Physics.Simulate(Time.fixedDeltaTime);
|
|
349
347
|
OnCaptureSnapshot?.Invoke(this.tickTimes[tickIndex], true);
|
|
@@ -165,7 +165,7 @@ namespace Code.Network.StateSystem
|
|
|
165
165
|
private void Awake()
|
|
166
166
|
{
|
|
167
167
|
AirshipSimulationManager.Instance.ActivateSimulationManager();
|
|
168
|
-
AirshipSimulationManager.Instance.
|
|
168
|
+
AirshipSimulationManager.Instance.OnTick += this.OnTick;
|
|
169
169
|
AirshipSimulationManager.Instance.OnSetSnapshot += this.OnSetSnapshot;
|
|
170
170
|
AirshipSimulationManager.Instance.OnCaptureSnapshot += this.OnCaptureSnapshot;
|
|
171
171
|
AirshipSimulationManager.Instance.OnLagCompensationCheck += this.OnLagCompensationCheck;
|
|
@@ -195,7 +195,7 @@ namespace Code.Network.StateSystem
|
|
|
195
195
|
|
|
196
196
|
public void OnDestroy()
|
|
197
197
|
{
|
|
198
|
-
AirshipSimulationManager.Instance.
|
|
198
|
+
AirshipSimulationManager.Instance.OnTick -= this.OnTick;
|
|
199
199
|
AirshipSimulationManager.Instance.OnSetSnapshot -= this.OnSetSnapshot;
|
|
200
200
|
AirshipSimulationManager.Instance.OnCaptureSnapshot -= this.OnCaptureSnapshot;
|
|
201
201
|
AirshipSimulationManager.Instance.OnLagCompensationCheck -= this.OnLagCompensationCheck;
|
|
@@ -282,8 +282,9 @@ namespace Code.Network.StateSystem
|
|
|
282
282
|
|
|
283
283
|
#region Top Level Event Functions
|
|
284
284
|
|
|
285
|
-
private void
|
|
286
|
-
|
|
285
|
+
private void OnTick(object timeObj, object replayObj) {
|
|
286
|
+
if (timeObj is not double time || replayObj is not bool replay) return;
|
|
287
|
+
|
|
287
288
|
// We are in shared mode
|
|
288
289
|
if (isServer && isClient)
|
|
289
290
|
{
|
|
@@ -27,7 +27,8 @@
|
|
|
27
27
|
"GUID:199bc21c5ec6a3e41b1d67e225a7bd04",
|
|
28
28
|
"GUID:30817c1a0e6d646d99c048fc403f5979",
|
|
29
29
|
"GUID:325984b52e4128546bc7558552f8b1d2",
|
|
30
|
-
"GUID:72872094b21c16e48b631b2224833d49"
|
|
30
|
+
"GUID:72872094b21c16e48b631b2224833d49",
|
|
31
|
+
"GUID:befe48b9a36afc04ea625c93daad910e"
|
|
31
32
|
],
|
|
32
33
|
"includePlatforms": [],
|
|
33
34
|
"excludePlatforms": [],
|
|
@@ -1,11 +1,15 @@
|
|
|
1
|
-
using System
|
|
1
|
+
using System;
|
|
2
|
+
using System.IO;
|
|
2
3
|
using System.IO.Compression;
|
|
4
|
+
using Code.Zstd;
|
|
3
5
|
|
|
4
6
|
public static class VoxelCompressUtil {
|
|
7
|
+
private const ulong ZstdScratchBufferSize = 1024 * 128;
|
|
8
|
+
|
|
5
9
|
/// <summary>
|
|
6
10
|
/// Compress the given stream to a byte array.
|
|
7
11
|
/// </summary>
|
|
8
|
-
public static byte[]
|
|
12
|
+
public static byte[] CompressToByteArrayV1(Stream stream) {
|
|
9
13
|
using var compressedStream = new MemoryStream();
|
|
10
14
|
using var compressor = new DeflateStream(compressedStream, CompressionMode.Compress);
|
|
11
15
|
|
|
@@ -22,7 +26,7 @@ public static class VoxelCompressUtil {
|
|
|
22
26
|
/// Decompress the compressed byte array into a new MemoryStream. The returned
|
|
23
27
|
/// stream must be disposed once done.
|
|
24
28
|
/// </summary>
|
|
25
|
-
public static MemoryStream
|
|
29
|
+
public static MemoryStream DecompressToMemoryStreamV1(byte[] data) {
|
|
26
30
|
var decompressedStream = new MemoryStream();
|
|
27
31
|
|
|
28
32
|
using var compressedStream = new MemoryStream(data);
|
|
@@ -34,4 +38,23 @@ public static class VoxelCompressUtil {
|
|
|
34
38
|
|
|
35
39
|
return decompressedStream;
|
|
36
40
|
}
|
|
41
|
+
|
|
42
|
+
/// <summary>
|
|
43
|
+
/// Compress the given data to a byte array.
|
|
44
|
+
/// </summary>
|
|
45
|
+
public static byte[] CompressToByteArrayV2(ReadOnlySpan<byte> data) {
|
|
46
|
+
using var zstd = new Zstd(ZstdScratchBufferSize);
|
|
47
|
+
var compressed = zstd.Compress(data, Zstd.MaxCompressionLevel);
|
|
48
|
+
return compressed;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/// <summary>
|
|
52
|
+
/// Decompress the compressed byte array into a new MemoryStream. The returned
|
|
53
|
+
/// stream must be disposed once done.
|
|
54
|
+
/// </summary>
|
|
55
|
+
public static MemoryStream DecompressToMemoryStreamV2(ReadOnlySpan<byte> data) {
|
|
56
|
+
using var zstd = new Zstd(ZstdScratchBufferSize);
|
|
57
|
+
var decompressed = zstd.Decompress(data);
|
|
58
|
+
return new MemoryStream(decompressed, false);
|
|
59
|
+
}
|
|
37
60
|
}
|
|
@@ -443,7 +443,7 @@ namespace VoxelWorldStuff {
|
|
|
443
443
|
/// </summary>
|
|
444
444
|
public void WriteTemporaryCollision(Vector3 position, bool hasCollision) {
|
|
445
445
|
if (hasCollision) {
|
|
446
|
-
VoxelWorldCollision.MakeCollider(this, position, Vector3Int.one);
|
|
446
|
+
VoxelWorldCollision.MakeCollider(this, Vector3Int.FloorToInt(position) + Vector3.one / 2, Vector3Int.one);
|
|
447
447
|
} else {
|
|
448
448
|
VoxelWorldCollision.RemoveSingleVoxelCollision(this, position);
|
|
449
449
|
}
|
|
@@ -6,7 +6,6 @@ using UnityEngine.Profiling;
|
|
|
6
6
|
using VoxelData = System.UInt16;
|
|
7
7
|
using BlockId = System.UInt16;
|
|
8
8
|
|
|
9
|
-
|
|
10
9
|
[Serializable]
|
|
11
10
|
[LuauAPI]
|
|
12
11
|
[CreateAssetMenu(fileName = "VoxelWorldSaveFile", menuName = "Airship/VoxelWorld/VoxelWorldSaveFile", order = 0)]
|
|
@@ -15,6 +14,7 @@ public class WorldSaveFile : ScriptableObject {
|
|
|
15
14
|
public List<BlockIdToScopedName> blockIdToScopeName = new();
|
|
16
15
|
|
|
17
16
|
public byte[] chunksCompressed;
|
|
17
|
+
[HideInInspector] public bool chunksCompressedV2;
|
|
18
18
|
|
|
19
19
|
[Serializable]
|
|
20
20
|
public struct BlockIdToScopedName {
|
|
@@ -131,9 +131,6 @@ public class WorldSaveFile : ScriptableObject {
|
|
|
131
131
|
}
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
134
|
public BlockId GetFileBlockIdFromStringId(string blockTypeId) {
|
|
138
135
|
foreach (var pair in this.blockIdToScopeName) {
|
|
139
136
|
if (pair.name == blockTypeId) {
|
|
@@ -216,7 +213,10 @@ public class WorldSaveFile : ScriptableObject {
|
|
|
216
213
|
}
|
|
217
214
|
|
|
218
215
|
// Compress:
|
|
219
|
-
|
|
216
|
+
var buffer = memStream.GetBuffer();
|
|
217
|
+
var bufferSpan = new ReadOnlySpan<byte>(buffer, 0, (int)memStream.Length);
|
|
218
|
+
chunksCompressed = VoxelCompressUtil.CompressToByteArrayV2(bufferSpan);
|
|
219
|
+
chunksCompressedV2 = true;
|
|
220
220
|
|
|
221
221
|
Profiler.EndSample();
|
|
222
222
|
|
|
@@ -299,7 +299,9 @@ public class WorldSaveFile : ScriptableObject {
|
|
|
299
299
|
|
|
300
300
|
// Decompress and deserialize chunks:
|
|
301
301
|
Profiler.BeginSample("DecompressChunks");
|
|
302
|
-
using var decompressedStream =
|
|
302
|
+
using var decompressedStream = chunksCompressedV2
|
|
303
|
+
? VoxelCompressUtil.DecompressToMemoryStreamV2(chunksCompressed)
|
|
304
|
+
: VoxelCompressUtil.DecompressToMemoryStreamV1(chunksCompressed);
|
|
303
305
|
Profiler.EndSample();
|
|
304
306
|
|
|
305
307
|
var reader = new BinaryReader(decompressedStream);
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
using System;
|
|
2
|
-
using System.
|
|
3
|
-
|
|
2
|
+
using System.Buffers;
|
|
4
3
|
using static Code.Zstd.ZstdNative;
|
|
5
4
|
|
|
6
5
|
namespace Code.Zstd {
|
|
@@ -33,32 +32,85 @@ namespace Code.Zstd {
|
|
|
33
32
|
/// and <c>Zstd.MaxCompressionLevel</c>. Most use-cases should use <c>Zstd.DefaultCompressionLevel</c>.
|
|
34
33
|
/// </summary>
|
|
35
34
|
public byte[] Compress(byte[] data, int compressionLevel) {
|
|
36
|
-
return
|
|
35
|
+
return Compress(new ReadOnlySpan<byte>(data), compressionLevel);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/// <summary>
|
|
39
|
+
/// Compress the data. The compression level can be between <c>Zstd.MinCompressionLevel</c>
|
|
40
|
+
/// and <c>Zstd.MaxCompressionLevel</c>. Most use-cases should use <c>Zstd.DefaultCompressionLevel</c>.
|
|
41
|
+
/// </summary>
|
|
42
|
+
public byte[] Compress(byte[] data, int start, int length, int compressionLevel) {
|
|
43
|
+
return Compress(new ReadOnlySpan<byte>(data, start, length), compressionLevel);
|
|
37
44
|
}
|
|
38
45
|
|
|
39
46
|
/// <summary>
|
|
40
47
|
/// Compress the data using the default compression level.
|
|
41
48
|
/// </summary>
|
|
42
49
|
public byte[] Compress(byte[] data) {
|
|
43
|
-
return
|
|
50
|
+
return Compress(new ReadOnlySpan<byte>(data));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/// <summary>
|
|
54
|
+
/// Compress the data using the default compression level.
|
|
55
|
+
/// </summary>
|
|
56
|
+
public byte[] Compress(byte[] data, int start, int length) {
|
|
57
|
+
return Compress(new ReadOnlySpan<byte>(data, start, length));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/// <summary>
|
|
61
|
+
/// Compress the data using the default compression level.
|
|
62
|
+
/// </summary>
|
|
63
|
+
public byte[] Compress(ReadOnlySpan<byte> data) {
|
|
64
|
+
return Compress(data, DefaultCompressionLevel);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/// <summary>
|
|
68
|
+
/// Compress the data. The compression level can be between <c>Zstd.MinCompressionLevel</c>
|
|
69
|
+
/// and <c>Zstd.MaxCompressionLevel</c>. Most use-cases should use <c>Zstd.DefaultCompressionLevel</c>.
|
|
70
|
+
/// </summary>
|
|
71
|
+
public byte[] Compress(ReadOnlySpan<byte> data, int compressionLevel) {
|
|
72
|
+
return CompressData(data, compressionLevel, _ctx);
|
|
44
73
|
}
|
|
45
74
|
|
|
46
75
|
/// <summary>
|
|
47
76
|
/// Decompress the data.
|
|
48
77
|
/// </summary>
|
|
49
78
|
public byte[] Decompress(byte[] data) {
|
|
79
|
+
return Decompress(new ReadOnlySpan<byte>(data));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/// <summary>
|
|
83
|
+
/// Decompress the data.
|
|
84
|
+
/// </summary>
|
|
85
|
+
public byte[] Decompress(byte[] data, int start, int length) {
|
|
86
|
+
return Decompress(new ReadOnlySpan<byte>(data, start, length));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/// <summary>
|
|
90
|
+
/// Decompress the data.
|
|
91
|
+
/// </summary>
|
|
92
|
+
public byte[] Decompress(ReadOnlySpan<byte> data) {
|
|
50
93
|
return DecompressData(data, _ctx);
|
|
51
94
|
}
|
|
52
95
|
|
|
53
96
|
public void Dispose() {
|
|
97
|
+
Dispose(true);
|
|
98
|
+
GC.SuppressFinalize(this);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
protected virtual void Dispose(bool disposing) {
|
|
54
102
|
_ctx.Dispose();
|
|
55
103
|
}
|
|
56
104
|
|
|
105
|
+
~Zstd() {
|
|
106
|
+
Dispose(false);
|
|
107
|
+
}
|
|
108
|
+
|
|
57
109
|
/// <summary>
|
|
58
110
|
/// Compress the bytes. The compression level can be between <c>Zstd.MinCompressionLevel</c>
|
|
59
111
|
/// and <c>Zstd.MaxCompressionLevel</c>. Most use-cases should use <c>Zstd.DefaultCompressionLevel</c>.
|
|
60
112
|
/// </summary>
|
|
61
|
-
public static byte[] CompressData(byte
|
|
113
|
+
public static byte[] CompressData(ReadOnlySpan<byte> data, int compressionLevel, ZstdContext ctx = null) {
|
|
62
114
|
var bound = ZSTD_compressBound((ulong)data.Length);
|
|
63
115
|
if (ZSTD_isError(bound)) {
|
|
64
116
|
throw new ZstdException(bound);
|
|
@@ -72,33 +124,34 @@ namespace Code.Zstd {
|
|
|
72
124
|
/// <summary>
|
|
73
125
|
/// Decompress the bytes.
|
|
74
126
|
/// </summary>
|
|
75
|
-
public static byte[] DecompressData(byte
|
|
76
|
-
|
|
77
|
-
|
|
127
|
+
public static unsafe byte[] DecompressData(ReadOnlySpan<byte> data, ZstdContext ctx = null) {
|
|
128
|
+
ulong rSize;
|
|
129
|
+
fixed (byte* src = data) {
|
|
130
|
+
rSize = ZSTD_getFrameContentSize(new IntPtr(src), (ulong)data.Length);
|
|
131
|
+
}
|
|
78
132
|
if (ZSTD_isError(rSize)) {
|
|
79
|
-
dataHandle.Free();
|
|
80
133
|
throw new ZstdException(rSize);
|
|
81
134
|
}
|
|
82
135
|
byte[] decompressedData;
|
|
83
136
|
if (rSize <= MaxStackSize) {
|
|
84
|
-
decompressedData = DecompressWithStack(data,
|
|
137
|
+
decompressedData = DecompressWithStack(data, rSize, ctx);
|
|
85
138
|
} else {
|
|
86
|
-
decompressedData = DecompressWithHeap(data,
|
|
139
|
+
decompressedData = DecompressWithHeap(data, rSize, ctx);
|
|
87
140
|
}
|
|
88
|
-
dataHandle.Free();
|
|
89
141
|
return decompressedData;
|
|
90
142
|
}
|
|
91
143
|
|
|
92
|
-
private static unsafe byte[] DecompressWithStack(byte
|
|
144
|
+
private static unsafe byte[] DecompressWithStack(ReadOnlySpan<byte> data, ulong rSize, ZstdContext ctx) {
|
|
93
145
|
var decompressedData = stackalloc byte[(int)rSize];
|
|
94
146
|
ulong decompressedSize;
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
147
|
+
fixed (byte* src = data) {
|
|
148
|
+
if (ctx != null) {
|
|
149
|
+
decompressedSize = ZSTD_decompressDCtx(ctx.Dctx, new IntPtr(decompressedData), rSize, new IntPtr(src), (ulong)data.Length);
|
|
150
|
+
} else {
|
|
151
|
+
decompressedSize = ZSTD_decompress(new IntPtr(decompressedData), rSize, new IntPtr(src), (ulong)data.Length);
|
|
152
|
+
}
|
|
99
153
|
}
|
|
100
154
|
if (ZSTD_isError(decompressedSize)) {
|
|
101
|
-
dataHandle.Free();
|
|
102
155
|
throw new ZstdException(decompressedSize);
|
|
103
156
|
}
|
|
104
157
|
var decompressedBuffer = new byte[decompressedSize];
|
|
@@ -108,35 +161,36 @@ namespace Code.Zstd {
|
|
|
108
161
|
return decompressedBuffer;
|
|
109
162
|
}
|
|
110
163
|
|
|
111
|
-
private static byte[] DecompressWithHeap(byte
|
|
164
|
+
private static unsafe byte[] DecompressWithHeap(ReadOnlySpan<byte> data, ulong rSize, ZstdContext ctx) {
|
|
112
165
|
var allocDst = ctx == null || rSize > (ulong)ctx.ScratchBuffer.Length;
|
|
113
166
|
var decompressedData = allocDst ? new byte[rSize] : ctx.ScratchBuffer;
|
|
114
|
-
var dstHandle = GCHandle.Alloc(decompressedData, GCHandleType.Pinned);
|
|
115
167
|
ulong decompressedSize;
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
168
|
+
fixed (byte* src = data) {
|
|
169
|
+
fixed (byte* dst = decompressedData) {
|
|
170
|
+
if (ctx != null) {
|
|
171
|
+
decompressedSize = ZSTD_decompressDCtx(ctx.Dctx, new IntPtr(dst), rSize, new IntPtr(src), (ulong)data.Length);
|
|
172
|
+
} else {
|
|
173
|
+
decompressedSize = ZSTD_decompress(new IntPtr(dst), rSize, new IntPtr(src), (ulong)data.Length);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
120
176
|
}
|
|
121
|
-
dstHandle.Free();
|
|
122
177
|
if (ZSTD_isError(decompressedSize)) {
|
|
123
|
-
dataHandle.Free();
|
|
124
178
|
throw new ZstdException(decompressedSize);
|
|
125
179
|
}
|
|
126
180
|
Array.Resize(ref decompressedData, (int)decompressedSize);
|
|
127
181
|
return decompressedData;
|
|
128
182
|
}
|
|
129
183
|
|
|
130
|
-
private static unsafe byte[] CompressWithStack(byte
|
|
184
|
+
private static unsafe byte[] CompressWithStack(ReadOnlySpan<byte> data, ulong bound, int compressionLevel, ZstdContext ctx) {
|
|
131
185
|
var dst = stackalloc byte[(int)bound];
|
|
132
|
-
var srcHandle = GCHandle.Alloc(data, GCHandleType.Pinned);
|
|
133
186
|
ulong compressedSize;
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
187
|
+
fixed (byte* src = data) {
|
|
188
|
+
if (ctx != null) {
|
|
189
|
+
compressedSize = ZSTD_compressCCtx(ctx.Cctx, new IntPtr(dst), bound, new IntPtr(src), (ulong)data.Length, compressionLevel);
|
|
190
|
+
} else {
|
|
191
|
+
compressedSize = ZSTD_compress(new IntPtr(dst), bound, new IntPtr(src), (ulong)data.Length, compressionLevel);
|
|
192
|
+
}
|
|
138
193
|
}
|
|
139
|
-
srcHandle.Free();
|
|
140
194
|
if (ZSTD_isError(compressedSize)) {
|
|
141
195
|
throw new ZstdException(compressedSize);
|
|
142
196
|
}
|
|
@@ -147,40 +201,59 @@ namespace Code.Zstd {
|
|
|
147
201
|
return compressedBuffer;
|
|
148
202
|
}
|
|
149
203
|
|
|
150
|
-
private static byte[] CompressWithHeap(byte
|
|
204
|
+
private static unsafe byte[] CompressWithHeap(ReadOnlySpan<byte> data, ulong bound, int compressionLevel, ZstdContext ctx) {
|
|
151
205
|
var allocDst = ctx == null || bound > (ulong)ctx.ScratchBuffer.Length;
|
|
152
|
-
var
|
|
153
|
-
var dstHandle = GCHandle.Alloc(dst, GCHandleType.Pinned);
|
|
154
|
-
var srcHandle = GCHandle.Alloc(data, GCHandleType.Pinned);
|
|
206
|
+
var dstBuf = allocDst ? new byte[bound] : ctx.ScratchBuffer;
|
|
155
207
|
ulong compressedSize;
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
208
|
+
fixed (byte* src = data) {
|
|
209
|
+
fixed (byte* dst = dstBuf) {
|
|
210
|
+
if (ctx != null) {
|
|
211
|
+
compressedSize = ZSTD_compressCCtx(ctx.Cctx, new IntPtr(dst), bound, new IntPtr(src), (ulong)data.Length, compressionLevel);
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
compressedSize = ZSTD_compress(new IntPtr(dst), bound, new IntPtr(src), (ulong)data.Length, compressionLevel);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
160
217
|
}
|
|
161
|
-
dstHandle.Free();
|
|
162
|
-
srcHandle.Free();
|
|
163
218
|
if (ZSTD_isError(compressedSize)) {
|
|
164
219
|
throw new ZstdException(compressedSize);
|
|
165
220
|
}
|
|
166
|
-
Array.Resize(ref
|
|
167
|
-
return
|
|
221
|
+
Array.Resize(ref dstBuf, (int)compressedSize);
|
|
222
|
+
return dstBuf;
|
|
168
223
|
}
|
|
169
224
|
}
|
|
170
225
|
|
|
171
|
-
public class ZstdContext : IDisposable {
|
|
226
|
+
public sealed class ZstdContext : IDisposable {
|
|
172
227
|
internal readonly byte[] ScratchBuffer;
|
|
173
228
|
|
|
174
229
|
internal readonly IntPtr Cctx;
|
|
175
230
|
internal readonly IntPtr Dctx;
|
|
231
|
+
|
|
232
|
+
private bool _disposed;
|
|
176
233
|
|
|
177
234
|
public ZstdContext(ulong scratchBufferSize) {
|
|
178
|
-
ScratchBuffer =
|
|
235
|
+
ScratchBuffer = ArrayPool<byte>.Shared.Rent((int)scratchBufferSize);
|
|
179
236
|
Cctx = ZSTD_createCCtx();
|
|
180
237
|
Dctx = ZSTD_createDCtx();
|
|
181
238
|
}
|
|
182
239
|
|
|
240
|
+
~ZstdContext() {
|
|
241
|
+
Dispose(false);
|
|
242
|
+
}
|
|
243
|
+
|
|
183
244
|
public void Dispose() {
|
|
245
|
+
Dispose(true);
|
|
246
|
+
GC.SuppressFinalize(this);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
private void Dispose(bool disposing) {
|
|
250
|
+
if (_disposed) return;
|
|
251
|
+
_disposed = true;
|
|
252
|
+
|
|
253
|
+
if (disposing) {
|
|
254
|
+
ArrayPool<byte>.Shared.Return(ScratchBuffer);
|
|
255
|
+
}
|
|
256
|
+
|
|
184
257
|
ZSTD_freeCCtx(Cctx);
|
|
185
258
|
ZSTD_freeDCtx(Dctx);
|
|
186
259
|
}
|
|
@@ -189,4 +262,9 @@ namespace Code.Zstd {
|
|
|
189
262
|
public class ZstdException : Exception {
|
|
190
263
|
public ZstdException(ulong code) : base(ZSTD_getErrorName(code)) { }
|
|
191
264
|
}
|
|
265
|
+
|
|
266
|
+
public class ZstdStreamException : Exception {
|
|
267
|
+
public ZstdStreamException(string message) : base(message) { }
|
|
268
|
+
public ZstdStreamException(ulong code) : this(ZSTD_getErrorName(code)) { }
|
|
269
|
+
}
|
|
192
270
|
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
using System;
|
|
2
|
+
using System.Buffers;
|
|
3
|
+
using System.IO;
|
|
4
|
+
using System.Runtime.InteropServices;
|
|
5
|
+
using static Code.Zstd.ZstdNative;
|
|
6
|
+
|
|
7
|
+
namespace Code.Zstd {
|
|
8
|
+
/// <summary>
|
|
9
|
+
/// Provides methods for compressing streams using the zstd algorithm.
|
|
10
|
+
/// </summary>
|
|
11
|
+
public sealed class ZstdCompressStream : Stream {
|
|
12
|
+
public override bool CanRead => false;
|
|
13
|
+
public override bool CanSeek => false;
|
|
14
|
+
public override bool CanWrite => true;
|
|
15
|
+
public override long Length => _compressedStream.Length;
|
|
16
|
+
public override long Position { get; set; }
|
|
17
|
+
|
|
18
|
+
private readonly Stream _compressedStream;
|
|
19
|
+
private readonly bool _leaveOpen;
|
|
20
|
+
|
|
21
|
+
private IntPtr _cctx;
|
|
22
|
+
private GCHandle _outHandle;
|
|
23
|
+
private readonly byte[] _bufOut;
|
|
24
|
+
private readonly ulong _bufOutSize;
|
|
25
|
+
|
|
26
|
+
private bool _disposed;
|
|
27
|
+
|
|
28
|
+
/// <summary>
|
|
29
|
+
/// Constructs a new ZstdCompressionStream.
|
|
30
|
+
/// </summary>
|
|
31
|
+
/// <param name="compressedStream">The stream to which compressed data is written.</param>
|
|
32
|
+
/// <param name="leaveOpen">Optionally leave the <c>compressedStream</c> open after closing (defaults to <c>false</c>).</param>
|
|
33
|
+
public ZstdCompressStream(Stream compressedStream, bool leaveOpen = false) : this(compressedStream, Zstd.DefaultCompressionLevel, leaveOpen) { }
|
|
34
|
+
|
|
35
|
+
/// <summary>
|
|
36
|
+
/// Constructs a new ZstdCompressionStream.
|
|
37
|
+
/// </summary>
|
|
38
|
+
/// <param name="compressedStream">The stream to which compressed data is written.</param>
|
|
39
|
+
/// <param name="compressionLevel">The zstd compression level. This should be in the range of <c>Zstd.MinCompressionLevel</c> and <c>Zstd.MaxCompressionLevel</c>. Most use-cases should use <c>Zstd.DefaultCompressionLevel</c>.</param>
|
|
40
|
+
/// <param name="leaveOpen">Optionally leave the <c>compressedStream</c> open after closing (defaults to <c>false</c>).</param>
|
|
41
|
+
public ZstdCompressStream(Stream compressedStream, int compressionLevel, bool leaveOpen = false) {
|
|
42
|
+
_compressedStream = compressedStream;
|
|
43
|
+
_leaveOpen = leaveOpen;
|
|
44
|
+
|
|
45
|
+
_cctx = ZSTD_createCCtx();
|
|
46
|
+
|
|
47
|
+
_bufOutSize = ZSTD_CStreamOutSize();
|
|
48
|
+
_bufOut = ArrayPool<byte>.Shared.Rent((int)_bufOutSize);
|
|
49
|
+
|
|
50
|
+
_outHandle = GCHandle.Alloc(_bufOut, GCHandleType.Pinned);
|
|
51
|
+
|
|
52
|
+
ZSTD_CCtx_setParameter(_cctx, ZSTD_cParameter.ZSTD_c_compressionLevel, compressionLevel);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
public override void Flush() {
|
|
56
|
+
var finished = false;
|
|
57
|
+
do {
|
|
58
|
+
var output = new ZSTD_outBuffer {
|
|
59
|
+
dst = _outHandle.AddrOfPinnedObject(),
|
|
60
|
+
size = _bufOutSize,
|
|
61
|
+
pos = 0,
|
|
62
|
+
};
|
|
63
|
+
var remaining = ZSTD_flushStream(_cctx, ref output);
|
|
64
|
+
if (ZSTD_isError(remaining)) {
|
|
65
|
+
throw new ZstdStreamException(remaining);
|
|
66
|
+
}
|
|
67
|
+
_compressedStream.Write(_bufOut, 0, (int)output.pos);
|
|
68
|
+
finished = remaining == 0;
|
|
69
|
+
} while (!finished);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
public override int Read(byte[] buffer, int offset, int count) {
|
|
73
|
+
throw new NotSupportedException();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
public override long Seek(long offset, SeekOrigin origin) {
|
|
77
|
+
throw new NotSupportedException();
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
public override void SetLength(long value) {
|
|
81
|
+
throw new NotSupportedException();
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
public override void Write(byte[] buffer, int offset, int count) {
|
|
85
|
+
WriteCore(new ReadOnlySpan<byte>(buffer, offset, count));
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
public override void Write(ReadOnlySpan<byte> buffer) {
|
|
89
|
+
WriteCore(buffer);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
private unsafe void WriteCore(ReadOnlySpan<byte> buffer) {
|
|
93
|
+
fixed (byte* bufferPtr = &MemoryMarshal.GetReference(buffer)) {
|
|
94
|
+
var input = new ZSTD_inBuffer {
|
|
95
|
+
src = (IntPtr)bufferPtr,
|
|
96
|
+
size = (ulong)buffer.Length,
|
|
97
|
+
pos = 0,
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
do {
|
|
101
|
+
var output = new ZSTD_outBuffer {
|
|
102
|
+
dst = _outHandle.AddrOfPinnedObject(),
|
|
103
|
+
size = _bufOutSize,
|
|
104
|
+
pos = 0,
|
|
105
|
+
};
|
|
106
|
+
var ret = ZSTD_compressStream(_cctx, ref output, ref input);
|
|
107
|
+
if (ZSTD_isError(ret)) {
|
|
108
|
+
throw new ZstdStreamException(ret);
|
|
109
|
+
}
|
|
110
|
+
_compressedStream.Write(_bufOut, 0, (int)output.pos);
|
|
111
|
+
} while (input.pos != input.size);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
protected override void Dispose(bool disposing) {
|
|
116
|
+
base.Dispose(disposing);
|
|
117
|
+
if (disposing && !_disposed) {
|
|
118
|
+
var finished = false;
|
|
119
|
+
do {
|
|
120
|
+
var output = new ZSTD_outBuffer {
|
|
121
|
+
dst = _outHandle.AddrOfPinnedObject(),
|
|
122
|
+
size = _bufOutSize,
|
|
123
|
+
pos = 0,
|
|
124
|
+
};
|
|
125
|
+
var remaining = ZSTD_endStream(_cctx, ref output);
|
|
126
|
+
if (ZSTD_isError(remaining)) {
|
|
127
|
+
throw new ZstdStreamException(remaining);
|
|
128
|
+
}
|
|
129
|
+
_compressedStream.Write(_bufOut, 0, (int)output.pos);
|
|
130
|
+
finished = remaining == 0;
|
|
131
|
+
} while (!finished);
|
|
132
|
+
|
|
133
|
+
_outHandle.Free();
|
|
134
|
+
ArrayPool<byte>.Shared.Return(_bufOut);
|
|
135
|
+
|
|
136
|
+
if (!_leaveOpen) {
|
|
137
|
+
_compressedStream.Close();
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
ZSTD_freeCCtx(_cctx);
|
|
142
|
+
_cctx = IntPtr.Zero;
|
|
143
|
+
|
|
144
|
+
_disposed = true;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
using System;
|
|
2
|
+
using System.Buffers;
|
|
3
|
+
using System.IO;
|
|
4
|
+
using System.Runtime.InteropServices;
|
|
5
|
+
using static Code.Zstd.ZstdNative;
|
|
6
|
+
|
|
7
|
+
namespace Code.Zstd {
|
|
8
|
+
/// <summary>
|
|
9
|
+
/// Provides methods for decompressing streams using the zstd algorithm.
|
|
10
|
+
/// </summary>
|
|
11
|
+
public sealed class ZstdDecompressStream : Stream {
|
|
12
|
+
public override bool CanRead => true;
|
|
13
|
+
public override bool CanSeek => false;
|
|
14
|
+
public override bool CanWrite => false;
|
|
15
|
+
public override long Length => _compressedStream.Length;
|
|
16
|
+
public override long Position { get; set; }
|
|
17
|
+
|
|
18
|
+
private readonly Stream _compressedStream;
|
|
19
|
+
private readonly bool _leaveOpen;
|
|
20
|
+
|
|
21
|
+
private IntPtr _dctx;
|
|
22
|
+
private GCHandle _outHandle;
|
|
23
|
+
private GCHandle _inHandle;
|
|
24
|
+
private readonly byte[] _bufOut;
|
|
25
|
+
private readonly byte[] _bufIn;
|
|
26
|
+
private readonly ulong _bufOutSize;
|
|
27
|
+
private readonly ulong _bufInSize;
|
|
28
|
+
|
|
29
|
+
private readonly MemoryStream _bufOutStream;
|
|
30
|
+
|
|
31
|
+
private int _currentBufOutOffset;
|
|
32
|
+
private int _currentBufIn;
|
|
33
|
+
|
|
34
|
+
private bool _disposed;
|
|
35
|
+
|
|
36
|
+
/// <summary>
|
|
37
|
+
/// Constructs a new ZstdDecompressionStream.
|
|
38
|
+
/// </summary>
|
|
39
|
+
/// <param name="compressedStream">The source stream from which compressed data is decompressed.</param>
|
|
40
|
+
/// <param name="leaveOpen">Optionally leave the <c>compressedStream</c> open after closing (defaults to <c>false</c>).</param>
|
|
41
|
+
public ZstdDecompressStream(Stream compressedStream, bool leaveOpen = false) {
|
|
42
|
+
_compressedStream = compressedStream;
|
|
43
|
+
_leaveOpen = leaveOpen;
|
|
44
|
+
|
|
45
|
+
_dctx = ZSTD_createDCtx();
|
|
46
|
+
|
|
47
|
+
_bufOutSize = ZSTD_DStreamOutSize();
|
|
48
|
+
_bufInSize = ZSTD_DStreamInSize();
|
|
49
|
+
|
|
50
|
+
_bufOut = ArrayPool<byte>.Shared.Rent((int)_bufOutSize);
|
|
51
|
+
_bufIn = ArrayPool<byte>.Shared.Rent((int)_bufInSize);
|
|
52
|
+
|
|
53
|
+
_outHandle = GCHandle.Alloc(_bufOut, GCHandleType.Pinned);
|
|
54
|
+
_inHandle = GCHandle.Alloc(_bufIn, GCHandleType.Pinned);
|
|
55
|
+
|
|
56
|
+
_bufOutStream = new MemoryStream((int)ZSTD_DStreamOutSize());
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
public override void Flush() {
|
|
60
|
+
throw new NotSupportedException();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
public override int Read(byte[] buffer, int offset, int count) {
|
|
64
|
+
return ReadCore(new Span<byte>(buffer, offset, count));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
public override int Read(Span<byte> buffer) {
|
|
68
|
+
return ReadCore(buffer);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
private int ReadCore(Span<byte> buffer) {
|
|
72
|
+
var read = 0;
|
|
73
|
+
var lastRet = 0ul;
|
|
74
|
+
var streamEmpty = false;
|
|
75
|
+
var bufferOffset = 0;
|
|
76
|
+
|
|
77
|
+
if (buffer.IsEmpty) {
|
|
78
|
+
throw new ZstdStreamException("Empty buffer");
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
while (true) {
|
|
82
|
+
if (_bufOutStream.Length > 0) {
|
|
83
|
+
var len = Math.Min(buffer.Length, (int)(_bufOutStream.Length - _currentBufOutOffset));
|
|
84
|
+
_bufOutStream.Seek(_currentBufOutOffset, SeekOrigin.Begin);
|
|
85
|
+
var bufOutRead = _bufOutStream.Read(buffer.Slice(bufferOffset, len));
|
|
86
|
+
if (bufOutRead != len) {
|
|
87
|
+
throw new ZstdStreamException("Failed to read full amount into buffer");
|
|
88
|
+
}
|
|
89
|
+
_currentBufOutOffset += len;
|
|
90
|
+
bufferOffset += len;
|
|
91
|
+
read += len;
|
|
92
|
+
|
|
93
|
+
if (_currentBufOutOffset == _bufOutStream.Length) {
|
|
94
|
+
_currentBufOutOffset = 0;
|
|
95
|
+
_bufOutStream.Seek(0, SeekOrigin.Begin);
|
|
96
|
+
_bufOutStream.SetLength(0);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (len == buffer.Length) {
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (_bufOutStream.Length == 0) {
|
|
105
|
+
if (_currentBufIn == 0) {
|
|
106
|
+
var bytesFromStream = ReadInCompressedChunkFromStream();
|
|
107
|
+
streamEmpty = bytesFromStream == 0;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (!streamEmpty) {
|
|
111
|
+
lastRet = Decompress();
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (streamEmpty && _bufOutStream.Length == 0) {
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (streamEmpty && _bufOutStream.Length == 0 && lastRet != 0) {
|
|
121
|
+
throw new ZstdStreamException($"EOF before end of stream: {lastRet}");
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return read;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
private ulong Decompress() {
|
|
128
|
+
var lastRet = 0ul;
|
|
129
|
+
|
|
130
|
+
var input = new ZSTD_inBuffer {
|
|
131
|
+
src = _inHandle.AddrOfPinnedObject(),
|
|
132
|
+
size = (ulong)_currentBufIn,
|
|
133
|
+
pos = 0,
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
while (input.pos < input.size) {
|
|
137
|
+
var output = new ZSTD_outBuffer {
|
|
138
|
+
dst = _outHandle.AddrOfPinnedObject(),
|
|
139
|
+
size = _bufOutSize,
|
|
140
|
+
pos = 0,
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
lastRet = ZSTD_decompressStream(_dctx, ref output, ref input);
|
|
144
|
+
if (ZSTD_isError(lastRet)) {
|
|
145
|
+
throw new ZstdStreamException(lastRet);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
_bufOutStream.Write(_bufOut, 0, (int)output.pos);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
_currentBufIn = 0;
|
|
152
|
+
|
|
153
|
+
return lastRet;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
private int ReadInCompressedChunkFromStream() {
|
|
157
|
+
var streamRead = 0;
|
|
158
|
+
if (_currentBufIn < (int)_bufInSize) {
|
|
159
|
+
streamRead = _compressedStream.Read(_bufIn, _currentBufIn, (int)_bufInSize - _currentBufIn);
|
|
160
|
+
_currentBufIn += streamRead;
|
|
161
|
+
}
|
|
162
|
+
return streamRead;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
public override long Seek(long offset, SeekOrigin origin) {
|
|
166
|
+
throw new NotSupportedException();
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
public override void SetLength(long value) {
|
|
170
|
+
throw new NotSupportedException();
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
public override void Write(byte[] buffer, int offset, int count) {
|
|
174
|
+
throw new NotSupportedException();
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
protected override void Dispose(bool disposing) {
|
|
178
|
+
base.Dispose(disposing);
|
|
179
|
+
if (disposing && !_disposed) {
|
|
180
|
+
_outHandle.Free();
|
|
181
|
+
_inHandle.Free();
|
|
182
|
+
ArrayPool<byte>.Shared.Return(_bufOut);
|
|
183
|
+
ArrayPool<byte>.Shared.Return(_bufIn);
|
|
184
|
+
if (!_leaveOpen) {
|
|
185
|
+
_compressedStream.Close();
|
|
186
|
+
}
|
|
187
|
+
_bufOutStream.Dispose();
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
ZSTD_freeDCtx(_dctx);
|
|
191
|
+
_dctx = IntPtr.Zero;
|
|
192
|
+
|
|
193
|
+
_disposed = true;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
@@ -327,7 +327,7 @@ namespace Code.Zstd {
|
|
|
327
327
|
#else
|
|
328
328
|
[DllImport("LuauPlugin")]
|
|
329
329
|
#endif
|
|
330
|
-
internal static extern ulong ZSTD_compressStream2(IntPtr cctx, ZSTD_outBuffer output, ZSTD_inBuffer input, ZSTD_EndDirective endOp);
|
|
330
|
+
internal static extern ulong ZSTD_compressStream2(IntPtr cctx, ref ZSTD_outBuffer output, ref ZSTD_inBuffer input, ZSTD_EndDirective endOp);
|
|
331
331
|
|
|
332
332
|
#if UNITY_IPHONE
|
|
333
333
|
[DllImport("__Internal")]
|
|
@@ -355,21 +355,21 @@ namespace Code.Zstd {
|
|
|
355
355
|
#else
|
|
356
356
|
[DllImport("LuauPlugin")]
|
|
357
357
|
#endif
|
|
358
|
-
internal static extern ulong ZSTD_compressStream(IntPtr zcs, ZSTD_outBuffer output, ZSTD_inBuffer input);
|
|
358
|
+
internal static extern ulong ZSTD_compressStream(IntPtr zcs, ref ZSTD_outBuffer output, ref ZSTD_inBuffer input);
|
|
359
359
|
|
|
360
360
|
#if UNITY_IPHONE
|
|
361
361
|
[DllImport("__Internal")]
|
|
362
362
|
#else
|
|
363
363
|
[DllImport("LuauPlugin")]
|
|
364
364
|
#endif
|
|
365
|
-
internal static extern ulong ZSTD_flushStream(IntPtr zcs, ZSTD_outBuffer output);
|
|
365
|
+
internal static extern ulong ZSTD_flushStream(IntPtr zcs, ref ZSTD_outBuffer output);
|
|
366
366
|
|
|
367
367
|
#if UNITY_IPHONE
|
|
368
368
|
[DllImport("__Internal")]
|
|
369
369
|
#else
|
|
370
370
|
[DllImport("LuauPlugin")]
|
|
371
371
|
#endif
|
|
372
|
-
internal static extern ulong ZSTD_endStream(IntPtr zcs, ZSTD_outBuffer output);
|
|
372
|
+
internal static extern ulong ZSTD_endStream(IntPtr zcs, ref ZSTD_outBuffer output);
|
|
373
373
|
|
|
374
374
|
#if UNITY_IPHONE
|
|
375
375
|
[DllImport("__Internal")]
|
|
@@ -397,7 +397,7 @@ namespace Code.Zstd {
|
|
|
397
397
|
#else
|
|
398
398
|
[DllImport("LuauPlugin")]
|
|
399
399
|
#endif
|
|
400
|
-
internal static extern ulong ZSTD_decompressStream(IntPtr zds, ZSTD_outBuffer output, ZSTD_inBuffer input);
|
|
400
|
+
internal static extern ulong ZSTD_decompressStream(IntPtr zds, ref ZSTD_outBuffer output, ref ZSTD_inBuffer input);
|
|
401
401
|
|
|
402
402
|
#if UNITY_IPHONE
|
|
403
403
|
[DllImport("__Internal")]
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|