-- Compression.hs: OpenPGP (RFC4880) compression and decompression
-- Copyright © 2012  Clint Adams
-- This software is released under the terms of the ISC license.
-- (See the LICENSE file).

module Codec.Encryption.OpenPGP.Compression (
   decompressPkt
 , compressPkts
) where

import qualified Codec.Compression.BZip as BZip
import qualified Codec.Compression.Zlib as Zlib
import qualified Codec.Compression.Zlib.Raw as ZlibRaw
import Codec.Encryption.OpenPGP.Serialize ()
import Codec.Encryption.OpenPGP.Types
import Data.ByteString (ByteString)
import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as BL
import Data.Serialize (get, put)
import Data.Serialize.Get (runGet)
import Data.Serialize.Put (runPut)

decompressPkt :: Pkt -> [Pkt]
decompressPkt (CompressedDataPkt algo bs') = case (runGet get . B.concat . BL.toChunks) (decompressPkt' algo bs') of
                       Left _ -> []
                       Right packs -> unBlock packs
    where
        decompressPkt' :: CompressionAlgorithm -> ByteString -> BL.ByteString
        decompressPkt' ZIP bs = ZlibRaw.decompress $ BL.fromChunks [bs]
        decompressPkt' ZLIB bs = Zlib.decompress $ BL.fromChunks [bs]
        decompressPkt' BZip2 bs = BZip.decompress $ BL.fromChunks [bs]
        decompressPkt' _ _ = error "Compression algorithm not supported"
decompressPkt p = [p]

compressPkts :: CompressionAlgorithm -> [Pkt] -> Pkt
compressPkts ca packs = do
    let bs' = runPut $ put (Block packs)
    let cbs = B.concat . BL.toChunks $ compressPkts' ca bs'
    CompressedDataPkt ca cbs
    where
        compressPkts' :: CompressionAlgorithm -> ByteString -> BL.ByteString
        compressPkts' ZIP bs = ZlibRaw.compress $ BL.fromChunks [bs]
        compressPkts' ZLIB bs = Zlib.compress $ BL.fromChunks [bs]
        compressPkts' BZip2 bs = BZip.compress $ BL.fromChunks [bs]
        compressPkts' _ _ = error "Compression algorithm not supported"