1
2
3
4
5
6 using System;
7 using System.IO;
8
9 namespace System.IO.Compression
10 {
11 public enum CompressionMode : int
12 {
13 compress = 0, decompress = 1
14 }
15
16 public const int defaultDeflateCompressionLevel = -1;
17 public const int noDeflateCompression = 0;
18 public const int fastestDeflateCompression = 1;
19 public const int optimalDeflateCompression = 9;
20 public const int Z_NO_FLUSH = 0;
21 public const int Z_STREAM_END = 1;
22 public const int Z_FINISH = 4;
23 public const int Z_STREAM_ERROR = -2;
24
25 public class DeflateStream : Stream
26 {
27 public DeflateStream(Stream* underlyingStream_, int compressionLevel_) : this(underlyingStream_, compressionLevel_, 16384)
28 {
29 }
30 public DeflateStream(Stream* underlyingStream_, CompressionMode mode_) : this(underlyingStream_, mode_, 16384)
31 {
32 }
33 public DeflateStream(Stream* underlyingStream_, int compressionLevel_, long bufferSize_) :
34 underlyingStream(underlyingStream_), mode(CompressionMode.compress), handle(null), inAvail(0u), bufferSize(bufferSize_),
35 in(bufferSize), outAvail(0u), outPos(0), outHave(0u), endOfInput(false), endOfStream(false), out(bufferSize)
36 {
37 int errorId = 0;
38 RtmInitZlib(mode, compressionLevel_, &handle, errorId);
39 if (errorId != 0)
40 {
41 SetErrorId(errorId);
42 }
43 }
44 public DeflateStream(Stream* underlyingStream_, CompressionMode mode_, long bufferSize_) :
45 underlyingStream(underlyingStream_), mode(mode_), handle(null), inAvail(0u), bufferSize(bufferSize_),
46 in(bufferSize), outAvail(0u), outPos(0), outHave(0u), endOfInput(false), endOfStream(false), out(bufferSize)
47 {
48 int errorId = 0;
49 RtmInitZlib(mode, defaultDeflateCompressionLevel, &handle, errorId);
50 if (errorId != 0)
51 {
52 SetErrorId(errorId);
53 }
54 }
55 suppress DeflateStream(DeflateStream&&);
56 suppress void operator=(DeflateStream&&);
57 suppress DeflateStream(const DeflateStream&);
58 suppress void operator=(const DeflateStream&);
59 public inline CompressionMode Mode() const
60 {
61 return mode;
62 }
63 public ~DeflateStream()
64 {
65 if (handle != null)
66 {
67 if (mode == CompressionMode.compress)
68 {
69 Finish();
70 }
71 RtmDoneZlib(mode, handle);
72 }
73 }
74 [nodiscard]
75 public override Result<int> ReadByte()
76 {
77 byte x = 0u;
78 auto readResult = this->Read(&x, 1);
79 if (readResult.Error())
80 {
81 return Result<int>(ErrorId(readResult.GetErrorId()));
82 }
83 long bytesRead = readResult.Value();
84 if (bytesRead == 0)
85 {
86 return Result<int>(-1);
87 }
88 return Result<int>(x);
89 }
90 [nodiscard]
91 public override Result<long> Read(byte* buf, long count)
92 {
93 if (mode != CompressionMode.decompress)
94 {
95 string errorMessage = "Cannot read from DeflateStream in CompressionMode.compress";
96 int errorId = AllocateError(errorMessage);
97 return Result<long>(ErrorId(errorId));
98 }
99 long bytesRead = 0;
100 do
101 {
102 if (inAvail == 0u && !endOfInput)
103 {
104 auto readResult = underlyingStream->Read(cast<byte*>(in.Mem()), bufferSize);
105 if (readResult.Error())
106 {
107 return Result<long>(ErrorId(readResult.GetErrorId()));
108 }
109 inAvail = cast<uint>(readResult.Value());
110 if (inAvail == 0u)
111 {
112 endOfInput = true;
113 }
114 RtmSetInputZlib(in.Mem(), inAvail, handle);
115 }
116 do
117 {
118 if (outHave == 0u && !endOfStream)
119 {
120 int errorId = 0;
121 int ret = RtmInflateZlib(out.Mem(), cast<uint>(bufferSize), &outHave, &outAvail, &inAvail, handle, errorId);
122 if (errorId != 0)
123 {
124 return Result<long>(ErrorId(errorId));
125 }
126 if (ret == Z_STREAM_END)
127 {
128 endOfStream = true;
129 }
130 outPos = 0;
131 }
132 while (count > 0 && outHave > 0u)
133 {
134 *buf++ = out[outPos++];
135 --count;
136 --outHave;
137 ++bytesRead;
138 }
139 }
140 while (count > 0 && outAvail == 0u);
141 }
142 while (count > 0 && !endOfStream && !endOfInput);
143 if (endOfInput && !endOfStream)
144 {
145 string errorMessage = "DeflateStream: unexpected end of input";
146 int errorId = AllocateError(errorMessage);
147 return Result<long>(ErrorId(errorId));
148 }
149 return Result<long>(bytesRead);
150 }
151 [nodiscard]
152 public override Result<bool> Write(byte x)
153 {
154 return this->Write(&x, 1);
155 }
156 [nodiscard]
157 public override Result<bool> Write(byte* buf, long count)
158 {
159 if (mode != CompressionMode.compress)
160 {
161 string errorMessage = "Cannot write to DeflateStream in CompressionMode.decompress";
162 int errorId = AllocateError(errorMessage);
163 return Result<bool>(ErrorId(errorId));
164 }
165 while (count > 0)
166 {
167 byte* inP = cast<byte*>(in.Mem());
168 inAvail = 0u;
169 while (count > 0 && inAvail < cast<uint>(bufferSize))
170 {
171 *inP++ = *buf++;
172 --count;
173 ++inAvail;
174 }
175 RtmSetInputZlib(in.Mem(), inAvail, handle);
176 do
177 {
178 uint have = 0u;
179 int errorId = 0;
180 int ret = RtmDeflateZlib(out.Mem(), cast<uint>(bufferSize), &have, &outAvail, handle, Z_NO_FLUSH, errorId);
181 if (errorId != 0)
182 {
183 return Result<bool>(ErrorId(errorId));
184 }
185 auto result = underlyingStream->Write(cast<byte*>(out.Mem()), cast<long>(have));
186 if (result.Error())
187 {
188 return Result<bool>(ErrorId(result.GetErrorId()));
189 }
190 }
191 while (outAvail == 0u);
192 }
193 return Result<bool>(true);
194 }
195 private Result<bool> Finish()
196 {
197 do
198 {
199 uint have = 0u;
200 int errorId = 0;
201 int ret = RtmDeflateZlib(out.Mem(), cast<uint>(bufferSize), &have, &outAvail, handle, Z_FINISH, errorId);
202 if (errorId != 0)
203 {
204 return Result<bool>(ErrorId(errorId));
205 }
206 auto result = underlyingStream->Write(cast<byte*>(out.Mem()), cast<long>(have));
207 if (result.Error())
208 {
209 return Result<bool>(ErrorId(result.GetErrorId()));
210 }
211 }
212 while (outAvail == 0);
213 return Result<bool>(true);
214 }
215 private Stream* underlyingStream;
216 private CompressionMode mode;
217 private long bufferSize;
218 private uint inAvail;
219 private IOBuffer in;
220 private uint outAvail;
221 private long outPos;
222 private uint outHave;
223 private bool endOfInput;
224 private bool endOfStream;
225 private IOBuffer out;
226 private void* handle;
227 }