public static string GetFileNameFromZipStream(this Stream stream, LocalHeader header) { Span <byte> buffer = stackalloc byte[header.FileNameLenght]; stream.Read(buffer); return(Encoding.UTF8.GetString(buffer)); }
public static void SkipExtraField(this Stream stream, LocalHeader header) { if (header.ExtraLenght != 0) { Span <byte> buffer = stackalloc byte[header.ExtraLenght]; stream.Read(buffer); } }
public static bool IsZip(this FileInfo info) { using FileStream contentStream = info.OpenRead(); return(LocalHeader.FromStream(contentStream).IsValid); }
private static void StoreFiles(Stream zipStream, IReadOnlyList <KeyValuePair <string, string> > files) { var isZip64 = false; var count = files.Count; var isZip64Count = !GetLegacyUInt16(count, out var legacyCount); isZip64 = isZip64 || isZip64Count; var relativeNames = new byte[count][]; var offsets = new long[count]; var methods = new CompressionMethod[count]; var times = new ushort[count]; var dates = new ushort[count]; var crc32s = new int[count]; var compressedLengths = new long[count]; var uncompressedLengths = new long[count]; //local entries and actual data Console.Write("Writing files."); for (int i = 0; i < count; i++) { Console.Write($"\rWriting files: {i + 1}/{count}"); offsets[i] = zipStream.Position; var location = files[i].Value; var relativeName = files[i].Key; var relativeNameBytes = relativeNames[i] = MiscHelpers.Encoding.GetBytes(relativeName); using (var file = File.OpenRead(location)) { var dateTime = File.GetLastWriteTime(file.Name); var uncompressedLength = uncompressedLengths[i] = file.Length; var compressedLength = compressedLengths[i] = file.Length; var isZip64CompressedLength = !GetLegacyUInt32(compressedLength, out var legacyCompressedLength); var isZip64UncompressedLength = !GetLegacyUInt32(uncompressedLength, out var legacyUncompressedLength); isZip64 = isZip64 || isZip64CompressedLength || isZip64UncompressedLength; var header = new LocalHeader { Signature = LocalHeader.DefaultSignature, VersionNeeded = ZipVersion, Flags = 0, Compression = methods[i] = CompressionMethod.Store, Time = times[i] = MiscHelpers.GetDosTime(dateTime), Date = dates[i] = MiscHelpers.GetDosDate(dateTime), Crc32 = crc32s[i] = file.ComputeCrc32(uncompressedLength), CompressedSize = legacyCompressedLength, UncompressedSize = legacyUncompressedLength, NameLength = MiscHelpers.EnsureFitsUInt16(relativeNameBytes.Length), ExtraLength = 0, }; if (isZip64CompressedLength || isZip64UncompressedLength) { header.ExtraLength = 4; if (isZip64CompressedLength) { header.ExtraLength += 8; } if (isZip64UncompressedLength) { header.ExtraLength += 8; } } zipStream.WriteValue(header); zipStream.Write(relativeNameBytes, 0, relativeNameBytes.Length); //zip64 extra if (isZip64CompressedLength || isZip64UncompressedLength) { WriteExtraZip64Header(zipStream, header.ExtraLength); if (isZip64UncompressedLength) { zipStream.WriteValue(uncompressedLengths[i]); } if (isZip64CompressedLength) { zipStream.WriteValue(compressedLengths[i]); } } file.Position = 0; file.CopyTo(zipStream); } } Console.WriteLine(); var directoryStart = zipStream.Position; var isZip64DirectoryStart = !GetLegacyUInt32(directoryStart, out var legacyDirectoryStart); isZip64 = isZip64 || isZip64DirectoryStart; //central directory entries Console.Write("Writing central directory."); for (int i = 0; i < count; i++) { Console.Write($"\rWriting central directory: {i + 1}/{count}"); var isZip64CompressedLength = !GetLegacyUInt32(compressedLengths[i], out var legacyCompressedLength); var isZip64UncompressedLength = !GetLegacyUInt32(uncompressedLengths[i], out var legacyUncompressedLength); var isZip64LocalOffset = !GetLegacyUInt32(offsets[i], out var legacyOffset); isZip64 = isZip64 || isZip64CompressedLength || isZip64UncompressedLength || isZip64LocalOffset; var relativeName = relativeNames[i]; var header = new DirectoryHeader { Signature = DirectoryHeader.DefaultSignature, VersionMadeBy = ZipVersion, VersionNeeded = ZipVersion, Flags = 0, Compression = methods[i], Time = times[i], Date = dates[i], Crc32 = crc32s[i], CompressedSize = legacyCompressedLength, UncompressedSize = legacyUncompressedLength, NameLength = (ushort)relativeName.Length, //gets checked when writing local headers ExtraLength = 0, CommentLength = 0, DiskNumber = 0, InternalAttributes = 0, ExternalAttributes = 0, LocalHeaderOffset = legacyOffset, }; if (isZip64CompressedLength || isZip64UncompressedLength || isZip64LocalOffset) { header.ExtraLength = 4; if (isZip64CompressedLength) { header.ExtraLength += 8; } if (isZip64UncompressedLength) { header.ExtraLength += 8; } if (isZip64LocalOffset) { header.ExtraLength += 8; } } zipStream.WriteValue(header); zipStream.Write(relativeName, 0, relativeName.Length); //zip64 extra if (header.ExtraLength > 0) { WriteExtraZip64Header(zipStream, header.ExtraLength); if (isZip64UncompressedLength) { zipStream.WriteValue(uncompressedLengths[i]); } if (isZip64CompressedLength) { zipStream.WriteValue(compressedLengths[i]); } if (isZip64LocalOffset) { zipStream.WriteValue(offsets[i]); } } } Console.WriteLine(); var directoryEnd = zipStream.Position; var directorySize = directoryEnd - directoryStart; var isZip64DirectorySize = !GetLegacyUInt32(directorySize, out var legacyDirectorySize); isZip64 = isZip64 || isZip64DirectorySize; if (isZip64) { var eod64 = new EndOfDirectory64 { Signature = EndOfDirectory64.DefaultSignature, Size = (ulong)(MiscHelpers.SizeOf <EndOfDirectory64> () - 4 - 8), VersionMadeBy = ZipVersion, VersionNeeded = ZipVersion, DiskNumber = 0, DirectoryDiskNumber = 0, DiskRecords = (ulong)count, TotalRecords = (ulong)count, DirectorySize = (ulong)directorySize, DirectoryOffset = (ulong)directoryStart, }; zipStream.WriteValue(eod64); var locator64 = new EndOfDirectory64Locator { Signature = EndOfDirectory64Locator.DefaultSignature, EndOfDirectory64DiskNumber = 0, EndOfDirectory64Offset = (ulong)directoryEnd, TotalDisks = 1, }; zipStream.WriteValue(locator64); } //central directory end var eod = new EndOfDirectory { Signature = EndOfDirectory.DefaultSignature, DiskNumber = 0, DirectoryDiskNumber = 0, DiskRecords = legacyCount, TotalRecords = legacyCount, DirectorySize = legacyDirectorySize, DirectoryOffset = legacyDirectoryStart, CommentLength = 0, }; zipStream.WriteValue(eod); }