zip 0.1.1 → 0.1.2
raw patch · 4 files changed
+71/−17 lines, 4 filesdep ~zip
Dependency ranges changed: zip
Files
- CHANGELOG.md +13/−0
- Codec/Archive/Zip/Internal.hs +38/−12
- tests/Main.hs +16/−1
- zip.cabal +4/−4
CHANGELOG.md view
@@ -1,3 +1,16 @@+## Zip 0.1.2++* Relaxed dependency on `semigroups`.++* Added explicit check of “version needed to extract”, so if archive uses+ some advanced features that we do not support yet, parsing fails.++* Value of “version needed to extract” field is now calculated dynamically+ with respect to actually used features, e.g. if you just store or deflate+ a not very big file, `2.0` version will be written (previously we wrote+ `4.6` unconditionally). This is needed to avoid scaring tools that can+ only handle basic Zip archives.+ ## Zip 0.1.1 * Make decoding of CP437 faster.
Codec/Archive/Zip/Internal.hs view
@@ -151,7 +151,7 @@ ---------------------------------------------------------------------------- -- Constants --- | Version to specify when writing archive data. For now it's a constant.+-- | “Version created by” to specify when writing archive data. zipVersion :: Version zipVersion = Version [4,6] []@@ -398,7 +398,7 @@ (GenericOrigin, _) -> Nothing (Borrowed ed, Nothing) -> edComment ed (Borrowed _, Just ()) -> Nothing- desc' = EntryDescription -- to write in local header+ desc0 = EntryDescription -- to write in local header { edVersionMadeBy = zipVersion , edVersionNeeded = zipVersion , edCompression = compression@@ -409,7 +409,7 @@ , edOffset = fromIntegral offset , edComment = M.lookup s eaEntryComment <|> oldComment , edExtraField = extraField }- B.hPut h (runPut (putHeader LocalHeader s desc'))+ B.hPut h (runPut (putHeader LocalHeader s desc0)) DataDescriptor {..} <- runResourceT $ if recompression then@@ -418,22 +418,25 @@ else src =$= decompressingPipe compressed $$ sinkData h compression else src $$ sinkData h Store afterStreaming <- hTell h- let desc = case o of- GenericOrigin -> desc'+ let desc1 = case o of+ GenericOrigin -> desc0 { edCRC32 = ddCRC32 , edCompressedSize = ddCompressedSize , edUncompressedSize = ddUncompressedSize }- Borrowed ed -> desc'+ Borrowed ed -> desc0 { edCRC32 = bool (edCRC32 ed) ddCRC32 recompression , edCompressedSize = bool (edCompressedSize ed) ddCompressedSize recompression , edUncompressedSize = bool (edUncompressedSize ed) ddUncompressedSize recompression }+ desc2 = desc1+ { edVersionNeeded =+ getZipVersion (needsZip64 desc1) (Just compression) } hSeek h AbsoluteSeek offset- B.hPut h (runPut (putHeader LocalHeader s desc))+ B.hPut h (runPut (putHeader LocalHeader s desc2)) hSeek h AbsoluteSeek afterStreaming- return (s, desc)+ return (s, desc2) -- | Create 'Sink' to stream data there. Once streaming is finished, return -- 'DataDescriptor' for the streamed data. The action /does not/ close given@@ -521,9 +524,13 @@ getSignature 0x02014b50 -- central file header signature versionMadeBy <- toVersion <$> getWord16le -- version made by versionNeeded <- toVersion <$> getWord16le -- version needed to extract+ when (versionNeeded > zipVersion) . fail $+ "Version required to extract the archive is "+ ++ showVersion versionNeeded ++ " (can do "+ ++ showVersion zipVersion ++ ")" bitFlag <- getWord16le -- general purpose bit flag- when (any (testBit bitFlag) [0,6,13]) $- fail "Encrypted archives are not supported"+ when (any (testBit bitFlag) [0,6,13]) . fail $+ "Encrypted archives are not supported" let needUnicode = testBit bitFlag 11 mcompression <- toCompressionMethod <$> getWord16le -- compression method modTime <- getWord16le -- last mod file time@@ -688,7 +695,8 @@ putWord32le 0x06064b50 -- zip64 end of central dir signature putWord64le 44 -- size of zip64 end of central dir record putWord16le (fromVersion zipVersion) -- version made by- putWord16le (fromVersion zipVersion) -- version needed to extract+ putWord16le (fromVersion $ getZipVersion True Nothing)+ -- ↑ version needed to extract putWord32le 0 -- number of this disk putWord32le 0 -- number of the disk with the start of the central directory putWord64le (fromIntegral totalCount) -- total number of entries (this disk)@@ -879,7 +887,7 @@ -- | Decode 'ByteString'. The first argument indicates whether we should -- treat it as UTF-8 (in case bit 11 of general-purpose bit flag is set), -- otherwise the function assumes CP437. Note that since not every stream of--- bytes constitute valid UTF-8 text, this function can fail. In that case+-- bytes constitutes valid UTF-8 text, this function can fail. In that case -- 'Nothing' is returned. decodeText@@ -925,6 +933,24 @@ fromCompressionMethod Store = 0 fromCompressionMethod Deflate = 8 fromCompressionMethod BZip2 = 12++-- | Check if entry with these parameters needs Zip64 extension.++needsZip64 :: EntryDescription -> Bool+needsZip64 EntryDescription {..} = any (>= 0xffffffff)+ [edOffset, edCompressedSize, edUncompressedSize]++-- | Determine “version needed to extract” that should be written headers+-- given need of Zip64 feature and compression method.++getZipVersion :: Bool -> Maybe CompressionMethod -> Version+getZipVersion zip64 m = max zip64ver mver+ where zip64ver = makeVersion (if zip64 then [4,5] else [2,0])+ mver = makeVersion $ case m of+ Nothing -> [2,0]+ Just Store -> [2,0]+ Just Deflate -> [2,0]+ Just BZip2 -> [4,6] -- | Return decompressing 'Conduit' corresponding to given compression -- method.
tests/Main.hs view
@@ -52,6 +52,7 @@ import Data.Monoid import Data.Text (Text) import Data.Time+import Data.Version import Path import Path.IO import System.IO@@ -84,6 +85,7 @@ describe "withArchive" withArchiveSpec describe "archive comment" archiveCommentSpec describe "getEntryDesc" getEntryDescSpec+ describe "version needed" versionNeededSpec describe "addEntry" addEntrySpec describe "sinkEntry" sinkEntrySpec describe "loadEntry" loadEntrySpec@@ -99,7 +101,7 @@ describe "undoEntryChanges" undoEntryChangesSpec describe "undoArchiveChanges" undoArchiveChangesSpec describe "undoAll" undoAllSpec- describe "consistencySpec" consistencySpec+ describe "consistency" consistencySpec describe "packDirRecur" packDirRecurSpec describe "unpackInto" unpackIntoSpec @@ -325,6 +327,19 @@ \path -> property $ \(EM s desc z) -> do desc' <- fromJust <$> createArchive path (z >> commit >> getEntryDesc s) desc' `shouldSatisfy` softEq desc++versionNeededSpec :: SpecWith (Path Abs File)+versionNeededSpec =+ it "writes correct version that is needed to extract archive" $+ -- NOTE for now we check only how version depends on compression method,+ -- it should be mentioned that the version also depends on Zip64 feature+ \path -> property $ \(EM s desc z) -> do+ desc' <- fromJust <$> createArchive path (z >> commit >> getEntryDesc s)+ edVersionNeeded desc' `shouldBe` makeVersion+ (case edCompression desc of+ Store -> [2,0]+ Deflate -> [2,0]+ BZip2 -> [4,6]) addEntrySpec :: SpecWith (Path Abs File) addEntrySpec =
zip.cabal view
@@ -31,7 +31,7 @@ -- POSSIBILITY OF SUCH DAMAGE. name: zip-version: 0.1.1+version: 0.1.2 cabal-version: >= 1.10 license: BSD3 license-file: LICENSE.md@@ -72,7 +72,7 @@ , time >= 1.4 && < 1.7 , transformers >= 0.4 && < 0.6 if !impl(ghc >= 8.0)- build-depends: semigroups == 0.18.*+ build-depends: semigroups >= 0.16 default-extensions: RecordWildCards , TupleSections exposed-modules: Codec.Archive.Zip@@ -106,7 +106,7 @@ , text >= 0.2 && < 1.3 , time >= 1.4 && < 1.7 , transformers >= 0.4 && < 0.6- , zip >= 0.1.1+ , zip >= 0.1.2 default-language: Haskell2010 benchmark bench@@ -119,7 +119,7 @@ ghc-options: -O2 -Wall build-depends: base >= 4.8 && < 5 , criterion >= 1.0- , zip >= 0.1.1+ , zip >= 0.1.2 default-language: Haskell2010 source-repository head