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);
     }
 }
Exemple #3
0
 public static bool IsZip(this FileInfo info)
 {
     using FileStream contentStream = info.OpenRead();
     return(LocalHeader.FromStream(contentStream).IsValid);
 }
Exemple #4
0
        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);
        }