adamhathcock / sharpcompress

SharpCompress is a fully managed C# library to deal with many compression types and formats.
MIT License
2.27k stars 480 forks source link

Unzip file using IArchieve #504

Open ArunaVignesh opened 4 years ago

ArunaVignesh commented 4 years ago

Hi i am developing mobile app. i cant unzip some of the zip file using IArchieve.

I got the follwing exception SharpCompress cannot currently read non-seekable Zip Streams with encrypted data th at has been written in a non-seekable manner

If i am using ZipArchieve, it can open and read the file. If i want to write the zipEntry , zipentry.writetoDirectory method is missing. i got the answer that , it will not support on moble when google. What shall i do for write to directory.

i didnt get exception for all the zipfiles

SharpCompress.Archives.IArchive zipfiles = SharpCompress.Archives.ArchiveFactory.Open(zipFileName as string, options);
string unzipPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "..", "tmp", "unzip"); DirectoryInfo dirInfo = new DirectoryInfo(unzipPath);
foreach (var e in zipfiles.Entries) {
if (!e.IsDirectory) { SharpCompress.Archives.IArchiveEntryExtensions.WriteToDirectory(e, dirInfo.ToString(), new SharpCompress.Common.ExtractionOptions() { ExtractFullPath = true, Overwrite = true }); break; } }

adamhathcock commented 4 years ago

SharpCompress cannot currently read non-seekable Zip Streams with encrypted data th at has been written in a non-seekable manner

Is the error you get when using the Reader interface with a zip file that isn't formatted for non-seekable reading. Zip files have to be written with a trailer header on file entries and other information in the file header. This is data is optional in the spec so not all compressors do it.

ArunaVignesh commented 4 years ago

Is there any other way to solve optional header data problem? Is there any code changes need?

adamhathcock commented 4 years ago

Your zip files have to be written with the trailer header. Sharpcompress will do this with the Writer interface but it's all dependent upon the app that writes the zips. Otherwise, you'll just have to use the Archive interface.

The downside is that you have to have the complete file available to read the dictionary at the end of the zip to know about all the entries. Seeking to the correct file is fast though if the complete file is available.

ArunaVignesh commented 4 years ago

Is there any sample to convert the received non seekable zip file to seekable zip file(to add about all the entries at the end of zip file)?

In future, sharpcompress have any idea of support to write the non seekable encrypted zip file ?

adamhathcock commented 4 years ago

You can unzip with the Archive interface and create with the Writer interface. That will always make seekable archives. Examples can be found in the Tests

ArunaVignesh commented 4 years ago

Thank you for your suggestion. I checked your source and find out the solution. Your source working properly for the following changes.

Change need files for the following folder src/SharpCompress/Common/Zip/

1.ZipHeaderFactry.cs

Line 134 changed1 check FlagUtility.HasFlag(entryHeader.Flags, HeaderFlags.UsePostDataDescriptor) -> !FlagUtility.HasFlag(entryHeader.Flags, HeaderFlags.UsePostDataDescriptor)


 private void LoadHeader(ZipFileEntry entryHeader, Stream stream)
        {
            if (FlagUtility.HasFlag(entryHeader.Flags, HeaderFlags.Encrypted))
            {
                if (!entryHeader.IsDirectory && entryHeader.CompressedSize == 0 &&
                    !FlagUtility.HasFlag(entryHeader.Flags, HeaderFlags.UsePostDataDescriptor))
                {
                    throw new NotSupportedException("SharpCompress cannot currently read non-seekable Zip Streams with encrypted data that has been written in a non-seekable manner.");
                }

2.ZipFilePart.cs Line 136 Added 1 check

&& !FlagUtility.HasFlag(Header.Flags, HeaderFlags.UsePostDataDescriptor))


 protected Stream GetCryptoStream(Stream plainStream)
    {
        bool isFileEncrypted = FlagUtility.HasFlag(Header.Flags, HeaderFlags.Encrypted);

        if (Header.CompressedSize == 0 && isFileEncrypted 
            && !FlagUtility.HasFlag(Header.Flags, HeaderFlags.UsePostDataDescriptor))
        {
            throw new NotSupportedException("Cannot encrypt file with unknown size at start.");
        }

Reason is non-Seekable zip with encrypted file also supported in your following program ZipFilePart.cs file. But now the situation is your source is not working because ZipHeaderFactry.cs file line 134 throw exception and ZipFilePart.cs Line136 also throw exception . So this is not running further steps here after.

 if ((Header.CompressedSize == 0
                && FlagUtility.HasFlag(Header.Flags, HeaderFlags.UsePostDataDescriptor))
                || Header.IsZip64)
            {
                plainStream = new NonDisposingStream(plainStream); //make sure AES doesn't close
            }

May be many changes in new zip format for the following. We expect latest update your SharpCompress also. Newly added strong encryption (bit6, bit13) and etc.,

https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT

I have attached the changed file also. please refer..

can you add this changes in nuget packages... FileList.zip

adamhathcock commented 4 years ago

That’s not the best way to share code and submit fixes. Please read up on how to use GitHub and submit a pull request to this repository if you’ve got fixes to share. Thanks.