|
3 | 3 | using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
|
4 | 4 | using System;
|
5 | 5 | using System.IO;
|
6 |
| -using System.Text; |
| 6 | +using System.Linq; |
| 7 | +using System.Threading; |
| 8 | +using System.Threading.Tasks; |
7 | 9 |
|
8 | 10 | namespace ICSharpCode.SharpZipLib.GZip
|
9 | 11 | {
|
@@ -184,6 +186,30 @@ protected override void Dispose(bool disposing)
|
184 | 186 | }
|
185 | 187 | }
|
186 | 188 | }
|
| 189 | + |
| 190 | +#if NETSTANDARD2_1_OR_GREATER |
| 191 | + /// <inheritdoc cref="DeflaterOutputStream.DisposeAsync"/> |
| 192 | + public override async ValueTask DisposeAsync() |
| 193 | + { |
| 194 | + try |
| 195 | + { |
| 196 | + await FinishAsync(CancellationToken.None); |
| 197 | + } |
| 198 | + finally |
| 199 | + { |
| 200 | + if (state_ != OutputState.Closed) |
| 201 | + { |
| 202 | + state_ = OutputState.Closed; |
| 203 | + if (IsStreamOwner) |
| 204 | + { |
| 205 | + await baseOutputStream_.DisposeAsync(); |
| 206 | + } |
| 207 | + } |
| 208 | + |
| 209 | + await base.DisposeAsync(); |
| 210 | + } |
| 211 | + } |
| 212 | +#endif |
187 | 213 |
|
188 | 214 | /// <summary>
|
189 | 215 | /// Flushes the stream by ensuring the header is written, and then calling <see cref="DeflaterOutputStream.Flush">Flush</see>
|
@@ -218,74 +244,119 @@ public override void Finish()
|
218 | 244 | {
|
219 | 245 | state_ = OutputState.Finished;
|
220 | 246 | base.Finish();
|
221 |
| - |
222 |
| - var totalin = (uint)(deflater_.TotalIn & 0xffffffff); |
223 |
| - var crcval = (uint)(crc.Value & 0xffffffff); |
224 |
| - |
225 |
| - byte[] gzipFooter; |
226 |
| - |
227 |
| - unchecked |
228 |
| - { |
229 |
| - gzipFooter = new byte[] { |
230 |
| - (byte) crcval, (byte) (crcval >> 8), |
231 |
| - (byte) (crcval >> 16), (byte) (crcval >> 24), |
232 |
| - |
233 |
| - (byte) totalin, (byte) (totalin >> 8), |
234 |
| - (byte) (totalin >> 16), (byte) (totalin >> 24) |
235 |
| - }; |
236 |
| - } |
237 |
| - |
| 247 | + var gzipFooter = GetFooter(); |
238 | 248 | baseOutputStream_.Write(gzipFooter, 0, gzipFooter.Length);
|
239 | 249 | }
|
240 | 250 | }
|
| 251 | + |
| 252 | + /// <inheritdoc cref="Flush"/> |
| 253 | + public override async Task FlushAsync(CancellationToken ct) |
| 254 | + { |
| 255 | + await WriteHeaderAsync(); |
| 256 | + await base.FlushAsync(ct); |
| 257 | + } |
| 258 | + |
| 259 | + |
| 260 | + /// <inheritdoc cref="Finish"/> |
| 261 | + public override async Task FinishAsync(CancellationToken ct) |
| 262 | + { |
| 263 | + // If no data has been written a header should be added. |
| 264 | + if (state_ == OutputState.Header) |
| 265 | + { |
| 266 | + await WriteHeaderAsync(); |
| 267 | + } |
| 268 | + |
| 269 | + if (state_ == OutputState.Footer) |
| 270 | + { |
| 271 | + state_ = OutputState.Finished; |
| 272 | + await base.FinishAsync(ct); |
| 273 | + var gzipFooter = GetFooter(); |
| 274 | + await baseOutputStream_.WriteAsync(gzipFooter, 0, gzipFooter.Length, ct); |
| 275 | + } |
| 276 | + } |
241 | 277 |
|
242 | 278 | #endregion DeflaterOutputStream overrides
|
243 | 279 |
|
244 | 280 | #region Support Routines
|
245 | 281 |
|
246 |
| - private static string CleanFilename(string path) |
247 |
| - => path.Substring(path.LastIndexOf('/') + 1); |
248 |
| - |
249 |
| - private void WriteHeader() |
| 282 | + private byte[] GetFooter() |
250 | 283 | {
|
251 |
| - if (state_ == OutputState.Header) |
252 |
| - { |
253 |
| - state_ = OutputState.Footer; |
| 284 | + var totalin = (uint)(deflater_.TotalIn & 0xffffffff); |
| 285 | + var crcval = (uint)(crc.Value & 0xffffffff); |
254 | 286 |
|
255 |
| - var mod_time = (int)((DateTime.Now.Ticks - new DateTime(1970, 1, 1).Ticks) / 10000000L); // Ticks give back 100ns intervals |
256 |
| - byte[] gzipHeader = { |
257 |
| - // The two magic bytes |
258 |
| - GZipConstants.ID1, |
259 |
| - GZipConstants.ID2, |
| 287 | + byte[] gzipFooter; |
260 | 288 |
|
261 |
| - // The compression type |
262 |
| - GZipConstants.CompressionMethodDeflate, |
| 289 | + unchecked |
| 290 | + { |
| 291 | + gzipFooter = new [] { |
| 292 | + (byte) crcval, |
| 293 | + (byte) (crcval >> 8), |
| 294 | + (byte) (crcval >> 16), |
| 295 | + (byte) (crcval >> 24), |
| 296 | + (byte) totalin, |
| 297 | + (byte) (totalin >> 8), |
| 298 | + (byte) (totalin >> 16), |
| 299 | + (byte) (totalin >> 24), |
| 300 | + }; |
| 301 | + } |
263 | 302 |
|
264 |
| - // The flags (not set) |
265 |
| - (byte)flags, |
| 303 | + return gzipFooter; |
| 304 | + } |
266 | 305 |
|
267 |
| - // The modification time |
268 |
| - (byte) mod_time, (byte) (mod_time >> 8), |
269 |
| - (byte) (mod_time >> 16), (byte) (mod_time >> 24), |
| 306 | + private byte[] GetHeader() |
| 307 | + { |
| 308 | + var modTime = (int)((DateTime.Now.Ticks - new DateTime(1970, 1, 1).Ticks) / 10000000L); // Ticks give back 100ns intervals |
| 309 | + byte[] gzipHeader = { |
| 310 | + // The two magic bytes |
| 311 | + GZipConstants.ID1, |
| 312 | + GZipConstants.ID2, |
270 | 313 |
|
271 |
| - // The extra flags |
272 |
| - 0, |
| 314 | + // The compression type |
| 315 | + GZipConstants.CompressionMethodDeflate, |
273 | 316 |
|
274 |
| - // The OS type (unknown) |
275 |
| - 255 |
276 |
| - }; |
| 317 | + // The flags (not set) |
| 318 | + (byte)flags, |
277 | 319 |
|
278 |
| - baseOutputStream_.Write(gzipHeader, 0, gzipHeader.Length); |
| 320 | + // The modification time |
| 321 | + (byte) modTime, (byte) (modTime >> 8), |
| 322 | + (byte) (modTime >> 16), (byte) (modTime >> 24), |
279 | 323 |
|
280 |
| - if (flags.HasFlag(GZipFlags.FNAME)) |
281 |
| - { |
282 |
| - var fname = GZipConstants.Encoding.GetBytes(fileName); |
283 |
| - baseOutputStream_.Write(fname, 0, fname.Length); |
| 324 | + // The extra flags |
| 325 | + 0, |
284 | 326 |
|
285 |
| - // End filename string with a \0 |
286 |
| - baseOutputStream_.Write(new byte[] { 0 }, 0, 1); |
287 |
| - } |
| 327 | + // The OS type (unknown) |
| 328 | + 255 |
| 329 | + }; |
| 330 | + |
| 331 | + if (!flags.HasFlag(GZipFlags.FNAME)) |
| 332 | + { |
| 333 | + return gzipHeader; |
288 | 334 | }
|
| 335 | + |
| 336 | + |
| 337 | + return gzipHeader |
| 338 | + .Concat(GZipConstants.Encoding.GetBytes(fileName)) |
| 339 | + .Concat(new byte []{0}) // End filename string with a \0 |
| 340 | + .ToArray(); |
| 341 | + } |
| 342 | + |
| 343 | + private static string CleanFilename(string path) |
| 344 | + => path.Substring(path.LastIndexOf('/') + 1); |
| 345 | + |
| 346 | + private void WriteHeader() |
| 347 | + { |
| 348 | + if (state_ != OutputState.Header) return; |
| 349 | + state_ = OutputState.Footer; |
| 350 | + var gzipHeader = GetHeader(); |
| 351 | + baseOutputStream_.Write(gzipHeader, 0, gzipHeader.Length); |
| 352 | + } |
| 353 | + |
| 354 | + private async Task WriteHeaderAsync() |
| 355 | + { |
| 356 | + if (state_ != OutputState.Header) return; |
| 357 | + state_ = OutputState.Footer; |
| 358 | + var gzipHeader = GetHeader(); |
| 359 | + await baseOutputStream_.WriteAsync(gzipHeader, 0, gzipHeader.Length); |
289 | 360 | }
|
290 | 361 |
|
291 | 362 | #endregion Support Routines
|
|
0 commit comments