123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106 |
- using System;
- using System.IO;
- using System.Text;
- using SharpCompress.Common;
- using SharpCompress.Common.Zip;
- using SharpCompress.Common.Zip.Headers;
- using SharpCompress.Converters;
- namespace SharpCompress.Writers.Zip
- {
- internal class ZipCentralDirectoryEntry
- {
- private readonly ZipCompressionMethod compression;
- private readonly string fileName;
- private readonly ArchiveEncoding archiveEncoding;
- public ZipCentralDirectoryEntry(ZipCompressionMethod compression, string fileName, ulong headerOffset, ArchiveEncoding archiveEncoding)
- {
- this.compression = compression;
- this.fileName = fileName;
- HeaderOffset = headerOffset;
- this.archiveEncoding = archiveEncoding;
- }
- internal DateTime? ModificationTime { get; set; }
- internal string Comment { get; set; }
- internal uint Crc { get; set; }
- internal ulong Compressed { get; set; }
- internal ulong Decompressed { get; set; }
- internal ushort Zip64HeaderOffset { get; set; }
- internal ulong HeaderOffset { get; }
- internal uint Write(Stream outputStream)
- {
- byte[] encodedFilename = archiveEncoding.Encode(fileName);
- byte[] encodedComment = archiveEncoding.Encode(Comment);
- var zip64_stream = Compressed >= uint.MaxValue || Decompressed >= uint.MaxValue;
- var zip64 = zip64_stream || HeaderOffset >= uint.MaxValue || Zip64HeaderOffset != 0;
- var compressedvalue = zip64 ? uint.MaxValue : (uint)Compressed;
- var decompressedvalue = zip64 ? uint.MaxValue : (uint)Decompressed;
- var headeroffsetvalue = zip64 ? uint.MaxValue : (uint)HeaderOffset;
- var extralength = zip64 ? (2 + 2 + 8 + 8 + 8 + 4) : 0;
- var version = (byte)(zip64 ? 45 : 20); // Version 20 required for deflate/encryption
- HeaderFlags flags = Equals(archiveEncoding.GetEncoding(), Encoding.UTF8) ? HeaderFlags.Efs : HeaderFlags.None;
- if (!outputStream.CanSeek)
- {
- // Cannot use data descriptors with zip64:
- // https://blogs.oracle.com/xuemingshen/entry/is_zipinput_outputstream_handling_of
- // We check that streams are not written too large in the ZipWritingStream,
- // so this extra guard is not required, but kept to simplify changing the code
- // once the zip64 post-data issue is resolved
- if (!zip64_stream)
- flags |= HeaderFlags.UsePostDataDescriptor;
- if (compression == ZipCompressionMethod.LZMA)
- {
- flags |= HeaderFlags.Bit1; // eos marker
- }
- }
- //constant sig, then version made by, then version to extract
- outputStream.Write(new byte[] { 80, 75, 1, 2, version, 0, version, 0 }, 0, 8);
- outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)flags), 0, 2);
- outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)compression), 0, 2); // zipping method
- outputStream.Write(DataConverter.LittleEndian.GetBytes(ModificationTime.DateTimeToDosTime()), 0, 4);
- // zipping date and time
- outputStream.Write(DataConverter.LittleEndian.GetBytes(Crc), 0, 4); // file CRC
- outputStream.Write(DataConverter.LittleEndian.GetBytes(compressedvalue), 0, 4); // compressed file size
- outputStream.Write(DataConverter.LittleEndian.GetBytes(decompressedvalue), 0, 4); // uncompressed file size
- outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)encodedFilename.Length), 0, 2); // Filename in zip
- outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)extralength), 0, 2); // extra length
- outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)encodedComment.Length), 0, 2);
- outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)0), 0, 2); // disk=0
- outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)0), 0, 2); // file type: binary
- outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)0), 0, 2); // Internal file attributes
- outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)0x8100), 0, 2);
- // External file attributes (normal/readable)
- outputStream.Write(DataConverter.LittleEndian.GetBytes(headeroffsetvalue), 0, 4); // Offset of header
- outputStream.Write(encodedFilename, 0, encodedFilename.Length);
- if (zip64)
- {
- outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)0x0001), 0, 2);
- outputStream.Write(DataConverter.LittleEndian.GetBytes((ushort)(extralength - 4)), 0, 2);
- outputStream.Write(DataConverter.LittleEndian.GetBytes(Decompressed), 0, 8);
- outputStream.Write(DataConverter.LittleEndian.GetBytes(Compressed), 0, 8);
- outputStream.Write(DataConverter.LittleEndian.GetBytes(HeaderOffset), 0, 8);
- outputStream.Write(DataConverter.LittleEndian.GetBytes(0), 0, 4); // VolumeNumber = 0
- }
- outputStream.Write(encodedComment, 0, encodedComment.Length);
- return (uint)(8 + 2 + 2 + 4 + 4 + 4 + 4 + 2 + 2 + 2
- + 2 + 2 + 2 + 2 + 4 + encodedFilename.Length + extralength + encodedComment.Length);
- }
- }
- }
|