(???) / Write 1 file to a zip archive
(???) sing System.IO.Compression;
(???) sing System.IO.Hashing;
(???) / Zip data
(???) ar filename = "bananas.txt"u8.ToArray();
(???) ar filedata = "BANANABANANABANANABANANABANANA"u8.ToArray();
(???) ar fileComment = "file comment"u8.ToArray();
(???) ar comment = "zip comment"u8.ToArray();
(???) ar (date, time) = ToDos(DateTime.UtcNow);
(???) / Compress the data
(???) sing var outputStream = new MemoryStream();
(???) sing (var deflateStream = new DeflateStream(outputStream, CompressionLevel.Optimal))
(???)
(???) deflateStream.Write(filedata);
(???)
(???) ar data = outputStream.ToArray();
(???) / Create ZIP
(???) sing var zip = File.Create("minimal.zip");
(???) sing var output = new BinaryWriter(zip);
(???) / Calculate CRC-32/ISO-HDLC over the uncompressed data
(???) ar crc = new Crc32();
(???) rc.Append(filedata);
(???) ar crc32 = crc.GetCurrentHashAsUInt32();
(???) / Write file
(???) ar offset = WriteLocalFileHeader();
(???) riteData();
(???) / Write directory
(???) ar info = WriteCentralDirectoryHeader(offset);
(???) riteEndOfCentralDirectoryRecord(info.Position, info.Size);
(???) ong WriteLocalFileHeader()
(???)
(???) var currentPosition = output.BaseStream.Position;
(???) output.Write("PK\x03\x04".AsSpan());
(???) output.Write((ushort)(2 * 10)); // minimal version to extract
(???) output.Write((ushort)0); // general purpose bit flag
(???) output.Write((ushort)8); // compression method (0 = none, 8 = deflate)
(???) output.Write(time);
(???) output.Write(date);
(???) output.Write(crc32);
(???) output.Write((uint)data.Length); // compressed size
(???) output.Write((uint)filedata.Length); // uncompressed size
(???) output.Write((ushort)filename.Length);
(???) output.Write((ushort)0); // extra field length
(???) output.Write(filename);
(???) output.Write(Array.Empty<byte>()); // extra field
(???) return currentPosition;
(???)
(???) oid WriteData() => output.Write(data);
(???) onst ushort diskIndex = 0;
(???) onst ushort fileCount = 1;
(???) long Position, long Size) WriteCentralDirectoryHeader(long localHeaderOffset)
(???)
(???) var currentPosition = output.BaseStream.Position;
(???) output.Write("PK\x01\x02".AsSpan());
(???) output.Write((ushort)(2 * 10)); // version made by
(???) output.Write((ushort)(2 * 10)); // version needed to extract
(???) output.Write((ushort)0); // general purpose bit flag
(???) output.Write((ushort)8); // compression method (0 = none, 8 = deflate)
(???) output.Write(time);
(???) output.Write(date);
(???) output.Write(crc32);
(???) output.Write((uint)data.Length); // compressed size
(???) output.Write((uint)filedata.Length); // uncompressed size
(???) output.Write((ushort)filename.Length);
(???) output.Write((ushort)0); // extra field length
(???) output.Write((ushort)fileComment.Length);
(???) output.Write(diskIndex);
(???) output.Write((ushort)0); // internal file attributes (0 = binary)
(???) output.Write((uint)0b00100000); // external file attributes (MS-DOS™ archive)
(???) output.Write((uint)localHeaderOffset);
(???) output.Write(filename);
(???) output.Write(Array.Empty<byte>()); // extra field
(???) output.Write(fileComment);
(???) return (currentPosition, output.BaseStream.Position - currentPosition);
(???)
(???) oid WriteEndOfCentralDirectoryRecord(long centralDirectoryOffset, long size)
(???)
(???) output.Write("PK\x05\x06".AsSpan());
(???) output.Write(diskIndex); // current disk number
(???) output.Write(diskIndex); // disk where central directory starts
(???) output.Write(fileCount); // number of central directory records on this disk
(???) output.Write(fileCount); // total central directory records
(???) output.Write((uint)size); // total central directory records in bytes
(???) output.Write((uint)centralDirectoryOffset);
(???) output.Write((uint)comment.Length);
(???) output.Write(comment);
(???)
(???) / dates and times are in MS-DOS™ format
(???) ushort Date, ushort Time)ToDos(DateTime datetime) => (
(???) (ushort)((datetime.Year - 1980) << 9 | datetime.Month << 5 | datetime.Day),
(???) (ushort)(datetime.Hour << 11 | datetime.Minute << 5 | datetime.Second >> 1));