Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
Zip.cs
1using System;
3using System.IO;
4using System.IO.Compression;
6using System.Text;
7using System.Threading.Tasks;
9
10namespace Waher.Content.Zip
11{
21 public static class Zip
22 {
23 private const int PK_LOCAL_FILE_HEADER = 0x04034b50;
24 private const int PK_DATA_DESCRIPTOR = 0x08074b50;
25 private const int PK_CENTRAL_DIRECTORY_FILE_HEADER = 0x02014b50;
26 private const int PK_END_OF_CENTRAL_DIRECTORY = 0x06054b50;
27
33 public static Task CreateZipFile(string SourceFileName, string OutputFileName)
34 {
35 return CreateZipFile(SourceFileName, OutputFileName, null, ZipEncryption.None);
36 }
37
45 public static Task CreateZipFile(string SourceFileName,
46 string OutputFileName, string Password, ZipEncryption EncryptionMethod)
47 {
48 return CreateZipFile(SourceFileName, OutputFileName, false, Password,
49 EncryptionMethod);
50 }
51
59 public static Task CreateZipFile(string SourceFileName,
60 string OutputFileName, bool CreateFolder)
61 {
62 return CreateZipFile(SourceFileName, OutputFileName, CreateFolder, null,
63 ZipEncryption.None);
64 }
65
75 public static async Task CreateZipFile(string SourceFileName,
76 string OutputFileName, bool CreateFolder, string Password,
77 ZipEncryption EncryptionMethod)
78 {
79 if (CreateFolder)
80 {
81 string Folder = Path.GetDirectoryName(OutputFileName);
82 if (!Directory.Exists(Folder))
83 Directory.CreateDirectory(Folder);
84 }
85
86 DateTime LastWriteTime = File.GetLastWriteTime(SourceFileName);
87 using FileStream fs = File.OpenRead(SourceFileName);
88 using FileStream Output = File.Create(OutputFileName);
89
90 await CreateZipFile(SourceFileName, fs, LastWriteTime,
91 Output, Password, EncryptionMethod);
92 }
93
100 public static Task<byte[]> CreateZipFile(string SourceFileName,
101 byte[] SourceFileContents)
102 {
103 return CreateZipFile(SourceFileName, SourceFileContents, null,
104 ZipEncryption.None);
105 }
106
115 public static Task<byte[]> CreateZipFile(string SourceFileName,
116 byte[] SourceFileContents, string Password, ZipEncryption EncryptionMethod)
117 {
118 return CreateZipFile(SourceFileName, SourceFileContents,
119 DateTime.Now, Password, EncryptionMethod);
120 }
121
129 public static Task<byte[]> CreateZipFile(string SourceFileName,
130 byte[] SourceFileContents, DateTime SourceLastWriteTime)
131 {
132 return CreateZipFile(SourceFileName, SourceFileContents,
133 SourceLastWriteTime, null, ZipEncryption.None);
134 }
135
145 public static async Task<byte[]> CreateZipFile(string SourceFileName,
146 byte[] SourceFileContents, DateTime SourceLastWriteTime, string Password,
147 ZipEncryption EncryptionMethod)
148 {
149 using MemoryStream SourceFile = new MemoryStream(SourceFileContents);
150 using MemoryStream ZipFile = new MemoryStream();
151
152 await CreateZipFile(SourceFileName, SourceFile, SourceLastWriteTime,
153 ZipFile, Password, EncryptionMethod);
154
155 return ZipFile.ToArray();
156 }
157
165 public static Task CreateZipFile(string SourceFileName,
166 Stream SourceFileContents, DateTime SourceLastWriteTime, Stream Output)
167 {
168 return CreateZipFile(SourceFileName, SourceFileContents,
169 SourceLastWriteTime, Output, null, ZipEncryption.None);
170 }
171
181 public static Task CreateZipFile(string SourceFileName,
182 Stream SourceFileContents, DateTime SourceLastWriteTime, Stream Output,
183 string Password, ZipEncryption EncryptionMethod)
184 {
185 return CreateZipFile(new string[] { SourceFileName },
186 new Stream[] { SourceFileContents },
187 new DateTime[] { SourceLastWriteTime }, Output, Password, EncryptionMethod);
188 }
189
195 public static Task CreateZipFile(string[] SourceFileNames, string OutputFileName)
196 {
197 return CreateZipFile(SourceFileNames, OutputFileName, null, ZipEncryption.None);
198 }
199
207 public static Task CreateZipFile(string[] SourceFileNames,
208 string OutputFileName, string Password, ZipEncryption EncryptionMethod)
209 {
210 return CreateZipFile(SourceFileNames, OutputFileName, false, Password,
211 EncryptionMethod);
212 }
213
221 public static Task CreateZipFile(string[] SourceFileNames,
222 string OutputFileName, bool CreateFolder)
223 {
224 return CreateZipFile(SourceFileNames, OutputFileName, CreateFolder, null,
225 ZipEncryption.None);
226 }
227
237 public static async Task CreateZipFile(string[] SourceFileNames,
238 string OutputFileName, bool CreateFolder, string Password,
239 ZipEncryption EncryptionMethod)
240 {
241 if (CreateFolder)
242 {
243 string Folder = Path.GetDirectoryName(OutputFileName);
244 if (!Directory.Exists(Folder))
245 Directory.CreateDirectory(Folder);
246 }
247
248 int c = SourceFileNames.Length;
249 FileStream[] SourceFiles = new FileStream[c];
250 DateTime[] LastWriteTimes = new DateTime[c];
251 try
252 {
253 for (int i = 0; i < c; i++)
254 {
255 SourceFiles[i] = File.OpenRead(SourceFileNames[i]);
256 LastWriteTimes[i] = File.GetLastWriteTime(SourceFileNames[i]);
257 }
258
259 using FileStream Output = File.Create(OutputFileName);
260
261 await CreateZipFile(SourceFileNames, SourceFiles, LastWriteTimes,
262 Output, Password, EncryptionMethod);
263 }
264 finally
265 {
266 foreach (FileStream fs in SourceFiles)
267 fs?.Dispose();
268 }
269 }
270
277 public static Task<byte[]> CreateZipFile(string[] SourceFileNames,
278 byte[][] SourceFileContents)
279 {
280 return CreateZipFile(SourceFileNames, SourceFileContents, null,
281 ZipEncryption.None);
282 }
283
292 public static Task<byte[]> CreateZipFile(string[] SourceFileNames,
293 byte[][] SourceFileContents, string Password, ZipEncryption EncryptionMethod)
294 {
295 int c = SourceFileNames.Length;
296 DateTime[] LastWriteTimes = new DateTime[c];
297 DateTime Now = DateTime.Now;
298
299 for (int i = 0; i < c; i++)
300 LastWriteTimes[i] = Now;
301
302 return CreateZipFile(SourceFileNames, SourceFileContents,
303 LastWriteTimes, Password, EncryptionMethod);
304 }
305
313 public static Task<byte[]> CreateZipFile(string[] SourceFileNames,
314 byte[][] SourceFileContents, DateTime[] SourceLastWriteTimes)
315 {
316 return CreateZipFile(SourceFileNames, SourceFileContents,
317 SourceLastWriteTimes, null, ZipEncryption.None);
318 }
319
329 public static async Task<byte[]> CreateZipFile(string[] SourceFileNames,
330 byte[][] SourceFileContents, DateTime[] SourceLastWriteTimes, string Password,
331 ZipEncryption EncryptionMethod)
332 {
333 MemoryStream[] SourceFiles = new MemoryStream[SourceFileContents.Length];
334
335 try
336 {
337 for (int i = 0; i < SourceFileContents.Length; i++)
338 SourceFiles[i] = new MemoryStream(SourceFileContents[i]);
339
340 using MemoryStream ZipFile = new MemoryStream();
341
342 await CreateZipFile(SourceFileNames, SourceFiles, SourceLastWriteTimes,
343 ZipFile, Password, EncryptionMethod);
344
345 return ZipFile.ToArray();
346 }
347 finally
348 {
349 foreach (MemoryStream ms in SourceFiles)
350 ms?.Dispose();
351 }
352 }
353
361 public static Task CreateZipFile(IEnumerable<string> SourceFileNames,
362 IEnumerable<Stream> SourceFileContents, IEnumerable<DateTime> SourceLastWriteTimes,
363 Stream Output)
364 {
365 return CreateZipFile(SourceFileNames, SourceFileContents,
366 SourceLastWriteTimes, Output, null, ZipEncryption.None);
367 }
368
378 public static async Task CreateZipFile(IEnumerable<string> SourceFileNames,
379 IEnumerable<Stream> SourceFileContents, IEnumerable<DateTime> SourceLastWriteTimes,
380 Stream Output, string Password, ZipEncryption EncryptionMethod)
381 {
382 if (SourceFileNames is null)
383 throw new ArgumentNullException(nameof(SourceFileNames));
384
385 if (SourceFileContents is null)
386 throw new ArgumentNullException(nameof(SourceFileContents));
387
388 if (SourceLastWriteTimes is null)
389 throw new ArgumentNullException(nameof(SourceLastWriteTimes));
390
391 int Count = 0;
392 int FileIndex = 0;
393
394 foreach (string _ in SourceFileNames)
395 Count++;
396
397 if (Count > ushort.MaxValue)
398 throw new IOException("Too many entries for non-ZIP64 archive.");
399
400 IEnumerator<string> SourceFileNameEnumerator = SourceFileNames.GetEnumerator();
401 IEnumerator<Stream> SourceFileContentEnumerator = SourceFileContents.GetEnumerator();
402 IEnumerator<DateTime> SourceLastWriteTimeEnumerator = SourceLastWriteTimes.GetEnumerator();
403
404 bool Encrypt;
405
406 if (string.IsNullOrEmpty(Password))
407 {
408 if (EncryptionMethod != ZipEncryption.None)
409 throw new ArgumentException("Password not specified.", nameof(Password));
410
411 Encrypt = false;
412 }
413 else
414 {
415 if (EncryptionMethod == ZipEncryption.None)
416 throw new ArgumentException("Encryption method not specified.", nameof(EncryptionMethod));
417
418 Encrypt = true;
419 }
420
421 EntryMeta[] Entries = new EntryMeta[Count];
422
423 // §4.4.3 version needed to extract
424
425 ushort VersionToExtract = EncryptionMethod switch
426 {
427 ZipEncryption.Aes128Ae1 => 51, // v5.1 supports AES encryption
428 ZipEncryption.Aes192Ae1 => 51,
429 ZipEncryption.Aes256Ae1 => 51,
430 ZipEncryption.Aes128Ae2 => 51,
431 ZipEncryption.Aes192Ae2 => 51,
432 ZipEncryption.Aes256Ae2 => 51,
433 _ => 20 // v2.0 supports Deflate compression method
434 };
435
436 while (SourceFileNameEnumerator.MoveNext() &&
437 SourceFileContentEnumerator.MoveNext() &&
438 SourceLastWriteTimeEnumerator.MoveNext())
439 {
440 string SourceFileName = SourceFileNameEnumerator.Current;
441 Stream SourceFileContent = SourceFileContentEnumerator.Current;
442 DateTime SourceLastWriteTime = SourceLastWriteTimeEnumerator.Current;
443
444 SourceFileContent.Position = 0;
445
446 byte[] Bin = await SourceFileContent.ReadAllAsync();
447 int UncompressedSize = Bin.Length;
448 uint FileCrc32 = Crc32.Compute(Bin);
449 byte[] Compressed;
450
451 using (MemoryStream ms = new MemoryStream())
452 {
453 using (DeflateStream ds = new DeflateStream(ms, CompressionLevel.Optimal, true))
454 {
455 ds.Write(Bin, 0, UncompressedSize);
456 }
457
458 Compressed = ms.ToArray();
459 }
460
461 int CompressedSize0 = Compressed.Length;
462 int CompressedSizeTot = CompressedSize0;
463
464 string FileName = Path.GetFileName(SourceFileName);
465 byte[] FileNameBytes = Encoding.UTF8.GetBytes(FileName);
466 ushort FileNameLength = (ushort)FileNameBytes.Length;
467
468 if (FileNameLength > ushort.MaxValue)
469 throw new ArgumentException("Zip entry name too long: " + FileName, nameof(SourceFileNames));
470
471 // §4.4.4 general purpose bit flag
472 ushort Flags = 0x0800; // UTF-8 names.
473
474 byte[] Extra = null;
475 ushort ExtraLen = 0;
476 ushort CompressionMethod = 8; // Compression method: 8 = Deflate
477 bool DataDescriptor = false;
478
479 await Output.FlushAsync();
480 long HeaderOffset = Output.Position;
481 if (HeaderOffset > int.MaxValue)
482 throw new IOException("ZIP output too large (>2GB). ZIP64 is not implemented.");
483
484 int SaltLen = 0;
485 bool Ae2 = EncryptionMethod switch
486 {
487 ZipEncryption.Aes128Ae1 => false,
488 ZipEncryption.Aes192Ae1 => false,
489 ZipEncryption.Aes256Ae1 => false,
490 ZipEncryption.Aes128Ae2 => true,
491 ZipEncryption.Aes192Ae2 => true,
492 ZipEncryption.Aes256Ae2 => true,
493 _ => false,
494 };
495
496 if (Encrypt)
497 {
498 Flags |= 0x0001; // ZIP encryption.
499
500 if (EncryptionMethod == ZipEncryption.ZipCrypto)
501 CompressedSizeTot += 12;
502 else
503 {
504 Flags |= 0x08; // Bit 3: Use of a data descriptor.
505 CompressionMethod = 99; // PKWARE AES: local header method must be 99
506 DataDescriptor = true;
507
508 ushort AesVersion = EncryptionMethod switch
509 {
510 ZipEncryption.Aes128Ae1 => 0x0001,
511 ZipEncryption.Aes192Ae1 => 0x0001,
512 ZipEncryption.Aes256Ae1 => 0x0001,
513 ZipEncryption.Aes128Ae2 => 0x0002,
514 ZipEncryption.Aes192Ae2 => 0x0002,
515 ZipEncryption.Aes256Ae2 => 0x0002,
516 _ => throw new ArgumentException("Invalid ZIP encryption method.", nameof(EncryptionMethod))
517 };
518
519 byte Strength = EncryptionMethod switch
520 {
521 ZipEncryption.Aes128Ae1 => 1,
522 ZipEncryption.Aes128Ae2 => 1,
523 ZipEncryption.Aes192Ae1 => 2,
524 ZipEncryption.Aes192Ae2 => 2,
525 ZipEncryption.Aes256Ae1 => 3,
526 ZipEncryption.Aes256Ae2 => 3,
527 _ => throw new ArgumentException("Invalid ZIP encryption method.", nameof(EncryptionMethod))
528 };
529
530 SaltLen = Strength switch
531 {
532 1 => 8, // 128 bits
533 2 => 12, // 192 bits
534 3 => 16, // 256 bits
535 _ => throw new ArgumentException("Invalid ZIP encryption method.", nameof(EncryptionMethod))
536 };
537
538 Extra = new byte[]
539 {
540 0x01, 0x99, // ID = 0x9901
541 0x07, 0x00, // Data size = 7
542 (byte)AesVersion, 0x00, // AES Version
543 0x41, 0x45, // Vendor "AE" (0x4541)
544 Strength,
545 0x08, 0x00 // Deflate
546 };
547
548 ExtraLen = (ushort)Extra.Length;
549
550 CompressedSizeTot += SaltLen + 2;
551 if (Ae2 && UncompressedSize < 20)
552 FileCrc32 = 0; // To avoid leaking information about the file via the CRC. Ref: §IV: https://www.winzip.com/en/support/aes-encryption/
553
554 CompressedSizeTot += 10;
555 }
556
557 if (CompressedSizeTot < 0)
558 throw new IOException("ZIP output too large (>2GB). ZIP64 is not implemented.");
559 }
560
561 EntryMeta Entry = new EntryMeta()
562 {
563 FileNameBytes = FileNameBytes,
564 Flags = Flags,
565 CompressionMethod = CompressionMethod,
566 LastWriteTime = SourceLastWriteTime.ToDosTime(),
567 LastWriteDate = SourceLastWriteTime.ToDosDate(),
568 Crc32 = FileCrc32,
569 CompressedSize = CompressedSizeTot,
570 UncompressedSize = UncompressedSize,
571 HeaderOffset = (int)HeaderOffset,
572 Extra = Extra,
573 ExtraLen = ExtraLen
574 };
575 Entries[FileIndex++] = Entry;
576
577 // §4.3.7 Local file header:
578
579 Output.WriteUInt32(PK_LOCAL_FILE_HEADER);
580 Output.WriteUInt16(VersionToExtract);
581 Output.WriteUInt16(Flags); // General purpose bit flag: bit0=1 (encrypted), others 0 (0x0001)
582 Output.WriteUInt16(CompressionMethod);
583 Output.WriteUInt16(Entry.LastWriteTime);
584 Output.WriteUInt16(Entry.LastWriteDate);
585
586 if (DataDescriptor)
587 {
588 Output.WriteUInt32(0);
589 Output.WriteUInt32(0);
590 Output.WriteUInt32(0);
591 }
592 else
593 {
594 Output.WriteUInt32(FileCrc32);
595 Output.WriteUInt32((uint)CompressedSizeTot); // include encryption header in compressed size
596 Output.WriteUInt32((uint)UncompressedSize);
597 }
598
599 Output.WriteUInt16(FileNameLength); // File name length
600 Output.WriteUInt16(ExtraLen); // Extra field length
601 Output.Write(FileNameBytes, 0, FileNameBytes.Length);
602
603 if (ExtraLen > 0)
604 Output.Write(Extra, 0, ExtraLen);
605
606 if (Encrypt)
607 {
608 if (EncryptionMethod == ZipEncryption.ZipCrypto)
609 {
610 uint Key0 = 0x12345678;
611 uint Key1 = 0x23456789;
612 uint Key2 = 0x34567890;
613
614 foreach (char ch in Password)
615 {
616 if (ch > 255)
617 throw new ArgumentException("Password contains invalid character: " + ch.ToString(), nameof(Password));
618
619 UpdateKeys(ref Key0, ref Key1, ref Key2, (byte)ch);
620 }
621
622 using RandomNumberGenerator Rnd = RandomNumberGenerator.Create();
623 byte[] EncryptionHeader = new byte[12];
624
625 Rnd.GetBytes(EncryptionHeader, 0, 11);
626 EncryptionHeader[11] = (byte)(FileCrc32 >> 24);
627
628 // --- Write encrypted data: 12-byte header + compressed content ---
629
630 // Encrypt and write the 12-byte encryption header
631 foreach (byte b in EncryptionHeader)
632 {
633 byte EncryptedByte = EncryptByte(ref Key0, ref Key1, ref Key2, b);
634 Output.WriteByte(EncryptedByte);
635 }
636
637 // Encrypt and write the compressed file bytes
638 foreach (byte b in Compressed)
639 {
640 byte EncryptedByte = EncryptByte(ref Key0, ref Key1, ref Key2, b);
641 Output.WriteByte(EncryptedByte);
642 }
643 }
644 else // PKWARE AES (AE-1/AE-2)
645 {
646 int KeyLen = SaltLen << 1;
647 byte[] Salt = new byte[SaltLen];
648 using (RandomNumberGenerator rnd = RandomNumberGenerator.Create())
649 rnd.GetBytes(Salt);
650
651 // Derive key material with PBKDF2-HMAC-SHA1 (1000 iterations)
652
653 using Rfc2898DeriveBytes Pbkdf2 = new Rfc2898DeriveBytes(
654 Password, Salt, 1000, HashAlgorithmName.SHA1);
655
656 byte[] EncryptionKey = Pbkdf2.GetBytes(KeyLen);
657 byte[] MacKey = Pbkdf2.GetBytes(KeyLen);
658 byte[] PasswordVerifier = Pbkdf2.GetBytes(2);
659
660 // Write salt and password verifier
661 Output.Write(Salt, 0, SaltLen);
662 Output.Write(PasswordVerifier, 0, 2);
663
664 // AES-CTR encryption:
665 // Use AES-ECB to generate keystream blocks, XOR with payload.
666 // Counter block: 16 bytes, start counter at 1 in the last 4 bytes, big-endian increment.
667 byte[] EncryptedPayload = new byte[CompressedSize0];
668 using (Aes Aes = Aes.Create())
669 {
670 Aes.KeySize = KeyLen * 8;
671 Aes.BlockSize = 128;
672 Aes.Mode = CipherMode.ECB;
673 Aes.Padding = PaddingMode.None;
674
675 using ICryptoTransform Ecb = Aes.CreateEncryptor(EncryptionKey, new byte[16]);
676 byte[] CounterBin = new byte[16];
677 byte[] KeyStream = new byte[16];
678 int Offset = 0;
679 int BytesLeft = CompressedSize0;
680 int BlockSize = 16;
681 int i;
682
683 while (Offset < CompressedSize0)
684 {
685 i = 0;
686 while (++CounterBin[i] == 0)
687 i++;
688
689 Ecb.TransformBlock(CounterBin, 0, 16, KeyStream, 0);
690
691 if (BytesLeft < 16)
692 BlockSize = BytesLeft;
693
694 for (i = 0; i < BlockSize; i++, Offset++)
695 EncryptedPayload[Offset] = (byte)(Compressed[Offset] ^ KeyStream[i]);
696
697 BytesLeft -= BlockSize;
698 }
699 }
700
701 // Write encrypted payload
702 Output.Write(EncryptedPayload, 0, CompressedSize0);
703
704 // Write authentication code (first 10 bytes of HMAC-SHA1 over encrypted payload)
705
706 using HMACSHA1 Hmac = new HMACSHA1(MacKey);
707 byte[] Auth = Hmac.ComputeHash(EncryptedPayload);
708 Output.Write(Auth, 0, 10);
709 }
710 }
711 else
712 Output.Write(Compressed, 0, Compressed.Length);
713
714 if (DataDescriptor)
715 {
716 // §4.3.9 Data descriptor:
717
718 Output.WriteUInt32(PK_DATA_DESCRIPTOR);
719 Output.WriteUInt32(FileCrc32);
720 Output.WriteUInt32((uint)CompressedSizeTot); // include encryption header in compressed size
721 Output.WriteUInt32((uint)UncompressedSize);
722 }
723 }
724
725 if (FileIndex != Count)
726 throw new InvalidOperationException("Mismatched number of zip entries.");
727
728 // --- Write Central Directory File Header ---
729
730 // Record the offset where the central directory will start
731 await Output.FlushAsync();
732 long CentralDirOffset = Output.Position;
733 if (CentralDirOffset > int.MaxValue)
734 throw new IOException("ZIP output too large (>2GB). ZIP64 is not implemented.");
735
736 foreach (EntryMeta Entry in Entries)
737 {
738 // §4.3.12 Central directory structure:
739
740 Output.WriteUInt32(PK_CENTRAL_DIRECTORY_FILE_HEADER);
741 Output.WriteUInt16(VersionToExtract); // Version made by
742 Output.WriteUInt16(VersionToExtract); // Version needed to extract
743 Output.WriteUInt16(Entry.Flags); // General purpose bit flag (same as local: 0x0001 for encryption)
744 Output.WriteUInt16(Entry.CompressionMethod);
745 Output.WriteUInt16(Entry.LastWriteTime);
746 Output.WriteUInt16(Entry.LastWriteDate);
747 Output.WriteUInt32(Entry.Crc32);
748 Output.WriteUInt32((uint)Entry.CompressedSize);
749 Output.WriteUInt32((uint)Entry.UncompressedSize);
750
751 Output.WriteUInt16((ushort)Entry.FileNameBytes.Length); // File name length
752 Output.WriteUInt16(Entry.ExtraLen); // extra field length, file comment length
753 Output.WriteUInt16(0); // file comment length
754
755 Output.WriteUInt16(0); // Disk number start
756 Output.WriteUInt16(0); // internal file attrs
757 Output.WriteUInt32(0); // external attrs (0 for default)
758
759 Output.WriteUInt32((uint)Entry.HeaderOffset); // Relative offset of local header (start at 0 for this file)
760
761 Output.Write(Entry.FileNameBytes, 0, Entry.FileNameBytes.Length);
762
763 if (Entry.ExtraLen > 0)
764 Output.Write(Entry.Extra, 0, Entry.ExtraLen);
765
766 // No file comment
767 }
768
769
770 // --- Output.Write End of Central Directory (EOCD) record ---
771
772 await Output.FlushAsync();
773 uint CentralDirSize = (uint)(Output.Position - CentralDirOffset);
774
775 // §End of central directory record:
776
777 Output.WriteUInt32(PK_END_OF_CENTRAL_DIRECTORY);
778 Output.WriteUInt16(0); // Disk numbers (for single-disk archive, both 0)
779 Output.WriteUInt16(0); // Number of the disk with the start of the central directory
780 Output.WriteUInt16((ushort)Count); // Number of entries on this disk
781 Output.WriteUInt16((ushort)Count); // Total number of entries
782 Output.WriteUInt32(CentralDirSize); // Size of central directory
783 Output.WriteUInt32((uint)CentralDirOffset); // Offset of start of central directory
784 Output.WriteUInt16(0); // .ZIP file comment length (0 for no comment)
785
786 await Output.FlushAsync();
787 }
788
789 private struct EntryMeta
790 {
791 public byte[] FileNameBytes;
792 public ushort Flags;
793 public ushort CompressionMethod;
794 public ushort LastWriteTime;
795 public ushort LastWriteDate;
796 public uint Crc32;
797 public int CompressedSize;
798 public int UncompressedSize;
799 public int HeaderOffset;
800 public byte[] Extra;
801 public ushort ExtraLen;
802 }
803
811 private static void UpdateKeys(ref uint Key0, ref uint Key1, ref uint Key2, byte Value)
812 {
813 Key0 = Crc32.Update(Key0, Value);
814 Key1 += (byte)Key0;
815 Key1 = Key1 * 134775813 + 1;
816 Key2 = Crc32.Update(Key2, (byte)(Key1 >> 24));
817 }
818
827 private static byte EncryptByte(ref uint Key0, ref uint Key1, ref uint Key2, byte Value)
828 {
829 uint Temp = Key2 | 3;
830 byte KeyStreamByte = (byte)((Temp * (Temp ^ 1)) >> 8);
831 byte CipherByte = (byte)(Value ^ KeyStreamByte);
832 UpdateKeys(ref Key0, ref Key1, ref Key2, Value);
833 return CipherByte;
834 }
835
841 private static void WriteUInt16(this Stream Output, ushort Value)
842 {
843 Output.WriteByte((byte)Value);
844 Value >>= 8;
845 Output.WriteByte((byte)Value);
846 }
847
853 private static void WriteUInt32(this Stream Output, uint Value)
854 {
855 Output.WriteByte((byte)Value);
856 Value >>= 8;
857 Output.WriteByte((byte)Value);
858 Value >>= 8;
859 Output.WriteByte((byte)Value);
860 Value >>= 8;
861 Output.WriteByte((byte)Value);
862 }
863 }
864}
Static class for computing CRC-32 checksums.
Definition: Crc32.cs:7
static uint Update(uint Crc, byte Value)
Updates an existing CRC value with one byte (standard CRC-32 algorithm).
Definition: Crc32.cs:49
static uint Compute(byte[] Data)
Computes the CRC-32 of a byte array (polynomial 0xEDB88320, init = 0xFFFFFFFF, xor out = 0xFFFFFFFF).
Definition: Crc32.cs:33
Encapsulates a ZIP File
Definition: ZipFile.cs:7
Static class for creating ZIP files.
Definition: Zip.cs:22
static async Task< byte[]> CreateZipFile(string SourceFileName, byte[] SourceFileContents, DateTime SourceLastWriteTime, string Password, ZipEncryption EncryptionMethod)
Creates a ZIP file, possible password-protected, containing a single file.
Definition: Zip.cs:145
static Task CreateZipFile(string SourceFileName, Stream SourceFileContents, DateTime SourceLastWriteTime, Stream Output, string Password, ZipEncryption EncryptionMethod)
Creates a ZIP file, possible password-protected, containing a single file.
Definition: Zip.cs:181
static Task< byte[]> CreateZipFile(string SourceFileName, byte[] SourceFileContents, DateTime SourceLastWriteTime)
Creates a ZIP file containing a single file.
Definition: Zip.cs:129
static Task< byte[]> CreateZipFile(string[] SourceFileNames, byte[][] SourceFileContents, DateTime[] SourceLastWriteTimes)
Creates a ZIP file containing a single file.
Definition: Zip.cs:313
static Task CreateZipFile(string[] SourceFileNames, string OutputFileName)
Creates a ZIP file containing a single file.
Definition: Zip.cs:195
static Task CreateZipFile(string[] SourceFileNames, string OutputFileName, bool CreateFolder)
Creates a ZIP file containing a single file.
Definition: Zip.cs:221
static Task CreateZipFile(string SourceFileName, Stream SourceFileContents, DateTime SourceLastWriteTime, Stream Output)
Creates a ZIP file containing a single file.
Definition: Zip.cs:165
static async Task CreateZipFile(string SourceFileName, string OutputFileName, bool CreateFolder, string Password, ZipEncryption EncryptionMethod)
Creates a ZIP file, possible password-protected, containing a single file.
Definition: Zip.cs:75
static Task CreateZipFile(IEnumerable< string > SourceFileNames, IEnumerable< Stream > SourceFileContents, IEnumerable< DateTime > SourceLastWriteTimes, Stream Output)
Creates a ZIP file containing a single file.
Definition: Zip.cs:361
static async Task CreateZipFile(IEnumerable< string > SourceFileNames, IEnumerable< Stream > SourceFileContents, IEnumerable< DateTime > SourceLastWriteTimes, Stream Output, string Password, ZipEncryption EncryptionMethod)
Creates a ZIP file, possible password-protected, containing a single file.
Definition: Zip.cs:378
static Task CreateZipFile(string SourceFileName, string OutputFileName, bool CreateFolder)
Creates a ZIP file containing a single file.
Definition: Zip.cs:59
static Task< byte[]> CreateZipFile(string[] SourceFileNames, byte[][] SourceFileContents)
Creates a ZIP file containing a single file.
Definition: Zip.cs:277
static Task CreateZipFile(string[] SourceFileNames, string OutputFileName, string Password, ZipEncryption EncryptionMethod)
Creates a ZIP file, possible password-protected, containing a single file.
Definition: Zip.cs:207
static Task< byte[]> CreateZipFile(string SourceFileName, byte[] SourceFileContents, string Password, ZipEncryption EncryptionMethod)
Creates a ZIP file, possible password-protected, containing a single file.
Definition: Zip.cs:115
static Task CreateZipFile(string SourceFileName, string OutputFileName, string Password, ZipEncryption EncryptionMethod)
Creates a ZIP file, possible password-protected, containing a single file.
Definition: Zip.cs:45
static async Task< byte[]> CreateZipFile(string[] SourceFileNames, byte[][] SourceFileContents, DateTime[] SourceLastWriteTimes, string Password, ZipEncryption EncryptionMethod)
Creates a ZIP file, possible password-protected, containing a single file.
Definition: Zip.cs:329
static Task< byte[]> CreateZipFile(string[] SourceFileNames, byte[][] SourceFileContents, string Password, ZipEncryption EncryptionMethod)
Creates a ZIP file, possible password-protected, containing a single file.
Definition: Zip.cs:292
static Task CreateZipFile(string SourceFileName, string OutputFileName)
Creates a ZIP file containing a single file.
Definition: Zip.cs:33
static Task< byte[]> CreateZipFile(string SourceFileName, byte[] SourceFileContents)
Creates a ZIP file containing a single file.
Definition: Zip.cs:100
static async Task CreateZipFile(string[] SourceFileNames, string OutputFileName, bool CreateFolder, string Password, ZipEncryption EncryptionMethod)
Creates a ZIP file, possible password-protected, containing a single file.
Definition: Zip.cs:237
Definition: ImplTypes.g.cs:58
ZipEncryption
Enumeration containing ZIP Encryption methods.
Definition: ZipEncryption.cs:9