summaryrefslogtreecommitdiff
path: root/haskell/Data/XDelta.hsc
diff options
context:
space:
mode:
Diffstat (limited to 'haskell/Data/XDelta.hsc')
-rw-r--r--haskell/Data/XDelta.hsc47
1 files changed, 44 insertions, 3 deletions
diff --git a/haskell/Data/XDelta.hsc b/haskell/Data/XDelta.hsc
index 03785c0..4d9ffe2 100644
--- a/haskell/Data/XDelta.hsc
+++ b/haskell/Data/XDelta.hsc
@@ -16,7 +16,9 @@ import Data.Bits
16import qualified Data.ByteString as B 16import qualified Data.ByteString as B
17import qualified Data.ByteString.Unsafe as B 17import qualified Data.ByteString.Unsafe as B
18import qualified Data.ByteString.Internal as B 18import qualified Data.ByteString.Internal as B
19import qualified Data.ByteString.Lazy as L
19import Data.Coerce 20import Data.Coerce
21import qualified Data.IntMap as IntMap
20import Data.Monoid 22import Data.Monoid
21import Data.Primitive.Addr 23import Data.Primitive.Addr
22import Data.Primitive.ByteArray 24import Data.Primitive.ByteArray
@@ -258,8 +260,7 @@ withByteString d act =
258 in unsafeIOToPrim $ withForeignPtr fp $ \ptr -> unsafePrimToIO $ do 260 in unsafeIOToPrim $ withForeignPtr fp $ \ptr -> unsafePrimToIO $ do
259 act (ptr `plusPtr` off) (fromIntegral len) 261 act (ptr `plusPtr` off) (fromIntegral len)
260 262
261xdelta :: (PrimBase m, Monoid u) => XDeltaMethods m u -> (Stream m -> IO ErrorCode) -> [B.ByteString] 263xdelta :: (PrimBase m, Monoid u) => XDeltaMethods m u -> (Stream m -> m ErrorCode) -> [B.ByteString] -> m u
262 -> m u
263xdelta x xxcode_input ds = do 264xdelta x xxcode_input ds = do
264 mstream <- config_stream (xConfig x) 265 mstream <- config_stream (xConfig x)
265 either (\e _ -> xOnError x e "config_stream failed") 266 either (\e _ -> xOnError x e "config_stream failed")
@@ -274,7 +275,7 @@ xdelta x xxcode_input ds = do
274 avail_input stream indata len 275 avail_input stream indata len
275 go2 withBlk eof ds 276 go2 withBlk eof ds
276 go2 withBlk eof ds = do 277 go2 withBlk eof ds = do
277 ret <- withBlk $ unsafeIOToPrim $ xxcode_input stream 278 ret <- withBlk $ xxcode_input stream
278 case ret of 279 case ret of
279 XD3_INPUT -> if (not eof) then go withBlk ds else return mempty 280 XD3_INPUT -> if (not eof) then go withBlk ds else return mempty
280 XD3_OUTPUT -> do 281 XD3_OUTPUT -> do
@@ -299,3 +300,43 @@ xdelta x xxcode_input ds = do
299 s <- errorString stream 300 s <- errorString stream
300 xOnError x e s 301 xOnError x e s
301 go id ds 302 go id ds
303
304
305foreign import ccall "xdelta3.h xd3_decode_input" xd3_decode_input :: Ptr Xd3Stream -> IO ErrorCode
306foreign import ccall "xdelta3.h xd3_encode_input" xd3_encode_input :: Ptr Xd3Stream -> IO ErrorCode
307
308decode_input :: PrimMonad m => Stream m -> m ErrorCode
309decode_input stream =
310 unsafeIOToPrim $ xd3_decode_input (ptr $ mutableByteArrayContents $ streamArray stream)
311
312encode_input :: PrimMonad m => Stream m -> m ErrorCode
313encode_input stream =
314 unsafeIOToPrim $ xd3_encode_input (ptr $ mutableByteArrayContents $ streamArray stream)
315
316newtype XDelta = XDelta L.ByteString
317
318chunksOf :: Usize_t -> L.ByteString -> [B.ByteString]
319chunksOf len bs | L.null bs = []
320 | otherwise = let (b,bs') = L.splitAt (fromIntegral len) bs
321 in L.toStrict b : chunksOf len bs'
322
323computeDiff :: Config -> L.ByteString -> L.ByteString -> XDelta
324computeDiff cfg source patched = XDelta $ xdeltaPure cfg source patched
325
326applyPatch :: Config -> L.ByteString -> XDelta -> L.ByteString
327applyPatch cfg source (XDelta delta) = xdeltaPure cfg source delta
328
329xdeltaPure :: Config -> L.ByteString -> L.ByteString -> L.ByteString
330xdeltaPure cfg source delta =
331 let smap = IntMap.fromList $ zip [0..] (chunksOf 4096 source)
332 x :: XDeltaMethods (ST s) L.ByteString
333 x = XDeltaMethods
334 { xConfig = cfg
335 , xGetSource = (smap IntMap.!) . fromIntegral -- :: Xoff_t -> B.ByteString
336 , xOutput = \ptr len -> unsafeIOToST $ L.fromStrict <$> B.packCStringLen (castPtr ptr,len)
337 , xOnError = \e s -> return L.empty -- :: ErrorCode -> String -> m u
338 , xBlockSize = 4096 -- :: Usize_t
339 , xInterleave = id -- :: forall a. m a -> m a
340 }
341 ds = L.toChunks delta
342 in runST $ xdelta x decode_input ds