{-# LINE 1 "Data/BDelta.hsc" #-}
{-# LANGUAGE CPP, ForeignFunctionInterface #-}
{-# LINE 2 "Data/BDelta.hsc" #-}
-- |
-- Module:       Data.BDelta
-- Copyright:    (c) Joseph Adams 2011
-- License:      MIT
--
-- Maintainer:   joeyadams3.14159@gmail.com
-- Stability:    deprecated (renamed to bytestring-delta)
-- Portability:  unknown
--
-- This package has been renamed from bdelta to bytestring-delta, to avoid
-- conflicting with an existing project by the same name:
--
--  * <http://bdelta.org>
--
-- Please import Data.ByteString.Delta from the bytestring-delta package
-- instead.
--
-- Binary diff/patch for 'ByteString's.
--
-- The 'diff' function takes two 'ByteString's, and produces a \"patch\" that
-- can later be applied with the 'patch' function to the first string to produce
-- the second string.  It exploits common subsequences between the two strings,
-- and can be used to save bandwidth and disk space when many strings differing
-- by a small number of bytes need to be transmitted or stored.
--
-- Deltas produced by this version of the library can be applied using
-- current or future versions, but may not be compatible with past versions.
--
-- bdelta implements the algorithm described in
-- /An O(ND) Difference Algorithm and Its Variations/ by Eugene W. Myers.
-- Because its memory usage and expected running time are O(N + D^2),
-- it works well only when the strings differ by a small number of bytes.
-- This implementation stops trying when the strings differ by more than
-- 1000 bytes, and falls back to producing a patch that simply emits the new
-- string.
--
-- Thus, bdelta does not save any space when given two strings that differ by
-- more than 1000 bytes.  This may be improved in a future version of the
-- library.

module Data.BDelta
{-# DEPRECATED "bdelta has been renamed.  Please use package bytestring-delta instead." #-}
(
    diff,
    patch,
)
where


{-# LINE 51 "Data/BDelta.hsc" #-}

import Data.ByteString (ByteString, packCStringLen)
import Data.ByteString.Unsafe (unsafeUseAsCStringLen)
import Data.Int
import Data.Word
import Foreign (Ptr, alloca, peek)
import Foreign.C.String (CString, peekCAString)
import Foreign.C.Types

#if MIN_VERSION_base(4,4,0)
import Foreign.Marshal.Unsafe (unsafeLocalState)
#else
import System.IO.Unsafe (unsafePerformIO)

unsafeLocalState :: IO a -> a
unsafeLocalState = unsafePerformIO
#endif

type BDELTAcode = Int32
{-# LINE 70 "Data/BDelta.hsc" #-}

type BDeltaFunc = Ptr CChar       -> CSize
               -> Ptr CChar       -> CSize
               -> Ptr (Ptr CChar) -> Ptr CSize
               -> IO BDELTAcode

foreign import ccall safe "bdelta.h bdelta_diff"
    bdelta_diff :: BDeltaFunc

foreign import ccall safe "bdelta.h bdelta_patch"
    bdelta_patch :: BDeltaFunc

foreign import ccall unsafe "bdelta.h bdelta_strerror"
    bdelta_strerror :: BDELTAcode -> IO CString

-- I don't know if Foreign.Marshal.Alloc.free is guaranteed
-- to be compatible with stdlib's free or not.
foreign import ccall unsafe "stdlib.h free"
    free :: Ptr a -> IO ()

callBDeltaFunc :: BDeltaFunc -> ByteString -> ByteString -> Either BDELTAcode ByteString
callBDeltaFunc func old new =
    unsafeLocalState $
    unsafeUseAsCStringLen old $ \(oldPtr, oldSize) ->
    unsafeUseAsCStringLen new $ \(newPtr, newSize) ->
    alloca $ \diffPtrPtr ->
    alloca $ \diffSizePtr ->
    do
        rc <- func oldPtr     (fromIntegral oldSize)
                   newPtr     (fromIntegral newSize)
                   diffPtrPtr diffSizePtr
        case rc of
            0 -> do
{-# LINE 103 "Data/BDelta.hsc" #-}
                diffPtr <- peek diffPtrPtr
                diffSize <- peek diffSizePtr
                result <- packCStringLen (diffPtr, fromIntegral diffSize)
                free diffPtr
                return $ Right result
            _ -> return $ Left rc

strerror :: BDELTAcode -> String
strerror code = unsafeLocalState $ bdelta_strerror code >>= peekCAString

-- | Compute a delta between two 'ByteString's.
--
-- > patch old (diff old new) == Right new
diff :: ByteString -> ByteString -> ByteString
diff old new =
    case callBDeltaFunc bdelta_diff old new of
         Right result  -> result
         Left  errcode -> error $ "BDelta.diff: " ++ strerror errcode

-- | Apply a delta produced by 'diff'.
--
-- If the patch cannot be applied, this function returns @Left errmsg@,
-- where @errmsg@ is a string describing the error.
patch :: ByteString -> ByteString -> Either String ByteString
patch old patch_ =
    case callBDeltaFunc bdelta_patch old patch_ of
         Right result                               -> Right result
         Left (rc @ 2)  -> Left $ strerror rc
{-# LINE 131 "Data/BDelta.hsc" #-}
         Left (rc @ 3) -> Left $ strerror rc
{-# LINE 132 "Data/BDelta.hsc" #-}
         Left rc                                    -> error $ "BDelta.patch: " ++ strerror rc