dotnet / runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
https://docs.microsoft.com/dotnet/core/
MIT License
15.26k stars 4.73k forks source link

System.IO.Packaging.ZipArchive: No means to set the zip header bits 1 and 2 #88812

Closed maedula closed 6 months ago

maedula commented 1 year ago

Description

This is from a discussion as part of https://github.com/dotnet/Open-XML-SDK/issues/1443

there is no way to configure zip headers general purpose flags bit 1 and 2 via ZipArchive implementation. According to ISO 29500-2 OPC standard bit 1 and 2 are mandatory and reflect the applied zip compression.

Here is the meaning of those bits for deflate (as is used here): https://[pkware.cachefly.net/webdocs/APPNOTE/APPNOTE_6.2.0.txt](https://pkware.cachefly.net/webdocs/APPNOTE/APPNOTE_6.2.0.txt)

      (For Methods 8 and 9 - Deflating)
     Bit 2  Bit 1
       0      0    Normal (-en) compression option was used.
       0      1    Maximum (-exx/-ex) compression option was used.
       1      0    Fast (-ef) compression option was used.
       1      1    Super Fast (-es) compression option was used.

     Note:  Bits 1 and 2 are undefined if the compression
            method is any other.

These bits used to be set with a meaningful mapping via Open-XML-SDK when using .net framework

In the NETFx WindowsBase compression implementation this was set here: https://referencesource.microsoft.com/#WindowsBase/Base/MS/Internal/IO/Zip/ZipIOLocalFileHeader.cs,308 Based on the following mapping: https://referencesource.microsoft.com/#WindowsBase/Base/System/IO/Packaging/ZipPackage.cs,490

I´m suggesting that the ZipArchive implementation either set bits 1 & 2 as some mapping from CompressionLevel, or expose and API so that callers can specify the value for these bits.

Reproduction Steps

Using the Open XML SDK to reproduce this can be simple:

using System.IO.Packaging;

// Create a document by supplying the filepath. using (WordprocessingDocument wordDocument = WordprocessingDocument.Create(args[0], >WordprocessingDocumentType.Document))

...

wordDocument.Save();

Target .Net 7.0, 6.0, 5.0

Expected behavior

the ZipArchive implementation either set bits 1 & 2 as some mapping from CompressionLevel, or expose and API so that callers can specify the value for these bits.

Actual behavior

No means to set bits 1 & 2 at all

Regression?

I verified that .Net Framework maps CompressionLevel and turns on bit 1 & 2 in the same scenario with the test code above.

Known Workarounds

No response

Configuration

No response

Other information

No response

ghost commented 1 year ago

Tagging subscribers to this area: @dotnet/area-system-io-compression See info in area-owners.md if you want to be subscribed.

Issue Details
### Description This is from a discussion as part of https://github.com/dotnet/Open-XML-SDK/issues/1443 there is no way to configure zip headers general purpose flags bit 1 and 2 via ZipArchive implementation. According to ISO 29500-2 OPC standard bit 1 and 2 are mandatory and reflect the applied zip compression. Here is the meaning of those bits for deflate (as is used here): https://[pkware.cachefly.net/webdocs/APPNOTE/APPNOTE_6.2.0.txt](https://pkware.cachefly.net/webdocs/APPNOTE/APPNOTE_6.2.0.txt) > (For Methods 8 and 9 - Deflating) > Bit 2 Bit 1 > 0 0 Normal (-en) compression option was used. > 0 1 Maximum (-exx/-ex) compression option was used. > 1 0 Fast (-ef) compression option was used. > 1 1 Super Fast (-es) compression option was used. > > Note: Bits 1 and 2 are undefined if the compression > method is any other. These bits used to be set with a meaningful mapping via Open-XML-SDK when using .net framework In the NETFx WindowsBase compression implementation this was set here: https://referencesource.microsoft.com/#WindowsBase/Base/MS/Internal/IO/Zip/ZipIOLocalFileHeader.cs,308 Based on the following mapping: https://referencesource.microsoft.com/#WindowsBase/Base/System/IO/Packaging/ZipPackage.cs,490 I´m suggesting that the ZipArchive implementation either set bits 1 & 2 as some mapping from CompressionLevel, or expose and API so that callers can specify the value for these bits. ### Reproduction Steps Using the Open XML SDK to reproduce this can be simple: >using System.IO.Packaging; > >// Create a document by supplying the filepath. >using (WordprocessingDocument wordDocument = WordprocessingDocument.Create(args[0], >WordprocessingDocumentType.Document)) > >... > >wordDocument.Save(); ### Expected behavior the ZipArchive implementation either set bits 1 & 2 as some mapping from CompressionLevel, or expose and API so that callers can specify the value for these bits. ### Actual behavior No means to set bits 1 & 2 at all ### Regression? I verified that .Net Framework maps CompressionLevel and turns on bit 1 & 2 in the same scenario with the test code above. ### Known Workarounds _No response_ ### Configuration _No response_ ### Other information _No response_
Author: maedula
Assignees: -
Labels: `area-System.IO.Compression`, `untriaged`
Milestone: -
edwardneal commented 9 months ago

I'd like to work on this. We've not got DeflateOptionEnum in .NET Core, but I think we should map the CompressionLevel enum in System.IO.Compression to bits 1 & 2, as below:

Bit2 Bit1 .NET Framework CompressionOption .NET Core CompressionOption Proposed CompressionLevel
1 1 NotCompressed, SuperFast NotCompressed, SuperFast (proposed) NoCompression
1 0 Fast Fast, ~SuperFast~ (proposed) Fastest
0 1 Maximum ~N/A~, Maximum (proposed) SmallestSize
0 0 Normal Normal, ~Maximum~ (proposed) Optimal

To restore backwards compatibility from .NET Core to Framework, we should also change the mapping in System.IO.Packaging.ZipPackage's GetZipCompressionFromOpcCompressionOption method, such that CompressionOption.Maximum maps to CompressionLevel.SmallestSize and CompressionOption.SuperFast maps to CompressionLevel.NoCompression.