summaryrefslogtreecommitdiff
path: root/haskell/Data/VCDIFF/XDelta.hsc
diff options
context:
space:
mode:
authorJoe Crayne <joe@jerkface.net>2018-10-27 16:26:10 -0400
committerJoe Crayne <joe@jerkface.net>2018-10-27 16:26:10 -0400
commit4aab5a236e578f3cd97566bc142027e06e955f73 (patch)
tree9aeba26a693c8d17dfc66d6d98b2209a0be6b8b6 /haskell/Data/VCDIFF/XDelta.hsc
parent2d01ddf9bffb7be441e2cf1c7071240148839ab5 (diff)
build fix
Diffstat (limited to 'haskell/Data/VCDIFF/XDelta.hsc')
-rw-r--r--haskell/Data/VCDIFF/XDelta.hsc202
1 files changed, 202 insertions, 0 deletions
diff --git a/haskell/Data/VCDIFF/XDelta.hsc b/haskell/Data/VCDIFF/XDelta.hsc
new file mode 100644
index 0000000..6e32494
--- /dev/null
+++ b/haskell/Data/VCDIFF/XDelta.hsc
@@ -0,0 +1,202 @@
1{-# OPTIONS_GHC -Wno-partial-type-signatures #-}
2{-# LANGUAGE DataKinds #-}
3{-# LANGUAGE PartialTypeSignatures #-}
4{-# LANGUAGE TypeFamilies #-}
5module Data.VCDIFF.XDelta where
6
7import Control.Monad
8import Control.Monad.Primitive
9import Data.Bits
10import qualified Data.ByteString as B
11import Data.Coerce
12import Data.Int
13import Data.Primitive.ByteArray
14import Data.Primitive.ByteArray.Util
15import qualified Data.Text as T
16import Data.Text.Encoding
17import Data.VCDIFF.Types
18import Data.Word
19import Foreign.C.Types
20import Foreign.C.String
21import Foreign.Ptr
22
23#ifndef SIZEOF_SIZE_T
24#define SIZEOF_SIZE_T __SIZEOF_SIZE_T__
25#define SIZEOF_UNSIGNED_INT __SIZEOF_INT__
26#define SIZEOF_UNSIGNED_LONG __SIZEOF_LONG__
27#define SIZEOF_UNSIGNED_LONG_LONG __SIZEOF_LONG_LONG__
28#define static_assert(...)
29#endif
30#include <xdelta3.h>
31
32#include "offset.h"
33
34type instance SizeOf Usize_t = #const sizeof(usize_t)
35type instance SizeOf (FunPtr a) = #const sizeof(void(*)())
36type instance SizeOf (Ptr a) = #const sizeof(void*)
37type instance SizeOf #{type int} = #const sizeof(int)
38type instance SizeOf #{type unsigned int} = #const sizeof(unsigned int)
39
40
41data Xd3Source
42
43newtype Source m = Source (MutableByteArray (PrimState m))
44
45newSource :: PrimMonad m =>
46 String -- ^ name for debug/print purposes.
47 -> Usize_t -- ^ block size
48 -> Xoff_t -- ^ maximum visible buffer (Suggested: set same as block size).
49 -- Rounds up to approx 16k.
50 -> m (Source m)
51newSource nm blksz maxwinsz = do
52 let bsname = encodeUtf8 $ T.pack nm
53 src <- newPinnedByteArray $ 1 + B.length bsname + #{const sizeof(xd3_source)}
54 nptr <- writeStringAt src #{const sizeof(xd3_source)} bsname
55 writeAtByte src (#{off xd3_source, blksize }) blksz
56 writeAtByte src (#{off xd3_source, name }) nptr
57 writeAtByte src (#{off xd3_source, max_winsize}) maxwinsz
58 writeAtByte src (#{off xd3_source, curblkno }) (maxBound :: Xoff_t)
59 return $ Source src
60
61sourcePtr :: Source m -> Ptr Xd3Source
62sourcePtr (Source src) = ptr (mutableByteArrayContents src)
63
64sourceRequestedBlocknumber :: PrimMonad m => Source m -> m Xoff_t
65sourceRequestedBlocknumber (Source src) = readAtByte src (#{off xd3_source, getblkno})
66
67data CurrentBlock = CurrentBlock
68 { blkno :: !Xoff_t -- ^ current block number
69 , blkSize :: !Usize_t -- ^ number of bytes on current block: must be >= 0 and <= 'srcBlockSize'
70 , blkPtr :: !(Ptr Word8) -- ^ current block array
71 }
72
73sourceWriteCurrentBlock :: PrimMonad m => Source m -> CurrentBlock -> m ()
74sourceWriteCurrentBlock (Source src) (CurrentBlock no sz ptr) = do
75 writeAtByte src (#{off xd3_source, curblkno}) no
76 writeAtByte src (#{off xd3_source, onblk}) sz
77 writeAtByte src (#{off xd3_source, curblk}) ptr
78
79sourceWriteEOFKnown :: PrimMonad m => Source m -> Bool -> m ()
80sourceWriteEOFKnown (Source src) False = writeAtByte src (#{off xd3_source, eof_known}) (0 :: #{type int})
81sourceWriteEOFKnown (Source src) True = writeAtByte src (#{off xd3_source, eof_known}) (1 :: #{type int})
82
83newtype StreamArray m = StreamArray (MutableByteArray (PrimState m))
84
85newStreamArray :: PrimMonad m =>
86 Maybe String -> m (StreamArray m, CString)
87newStreamArray mmatcher = do
88 let (len,n) = case mmatcher of
89 Just m -> let n = encodeUtf8 $ T.pack m
90 in ( #{const sizeof(xd3_stream)} + B.length n + 1
91 , n )
92 Nothing -> ( #{const sizeof(xd3_stream)}, B.empty )
93 s <- newPinnedByteArray len
94 fillByteArray s 0 #{const sizeof(xd3_stream)} 0
95 nptr <- case mmatcher of
96 Nothing -> writeStringAt s #{const sizeof(xd3_stream)} n
97 Just _ -> return nullPtr
98 return (StreamArray s,nptr)
99
100streamArrayPtr :: StreamArray m -> Ptr Xd3Stream
101streamArrayPtr (StreamArray s) = ptr (mutableByteArrayContents s)
102
103setFlag :: PrimMonad m => Flags -> StreamArray m -> Bool -> m ()
104setFlag b (StreamArray s) wantFlush = do
105 f <- readAtByte s (#{off xd3_stream, flags})
106 writeAtByte s (#{off xd3_stream, flags})
107 . (coerce :: Flags -> Word32)
108 $ if wantFlush then Flags f .|. b
109 else Flags f .&. complement b
110
111setFlush :: PrimMonad m => StreamArray m -> Bool -> m ()
112setFlush = setFlag XD3_FLUSH
113
114setSkipWindow :: PrimMonad m => StreamArray m -> Bool -> m ()
115setSkipWindow = setFlag XD3_SKIP_WINDOW
116
117
118avail_input :: PrimMonad m => StreamArray m -> Ptr a -> Usize_t -> m ()
119avail_input (StreamArray s) p sz = do
120 writeAtByte s (#{off xd3_stream, next_in}) p
121 writeAtByte s (#{off xd3_stream, avail_in}) sz
122
123
124nextOut :: PrimMonad m => StreamArray m -> ((Ptr Word8, Usize_t) -> m a) -> m a
125nextOut (StreamArray s) action = do
126 buf <- (,)
127 <$> readAtByte s (#{off xd3_stream, next_out})
128 <*> readAtByte s (#{off xd3_stream, avail_out})
129 a <- action buf
130 -- unsafeIOToPrim $ xd3_consume_output (ptr $ mutableByteArrayContents $ streamArray stream)
131 writeAtByte s #{off xd3_stream, avail_out} (0 :: Usize_t)
132 return a
133
134
135-- | Gives some extra information about the latest library error, if any
136-- is known.
137errorString :: PrimMonad m => StreamArray m -> m String
138errorString (StreamArray s) = do
139 cstring <- readAtByte s (#{off xd3_stream, msg})
140 if cstring /= nullPtr
141 then unsafeIOToPrim $ peekCString cstring -- TODO: avoid unsafeIOToPrim
142 else return ""
143
144writeCompressorConfig :: (PrimMonad m, _) => MutableByteArray (PrimState m) -> Offset j -> CompressorConfig -> m ()
145writeCompressorConfig c o sec = do
146 writeAtByte c (o +. #{off xd3_sec_cfg,ngroups}) (ngroups sec)
147 writeAtByte c (o +. #{off xd3_sec_cfg,sector_size}) (sector_size sec)
148 writeAtByte c (o +. #{off xd3_sec_cfg,inefficient}) (inefficient sec)
149
150writeMatcher :: (PrimMonad m, _) => MutableByteArray (PrimState m) -> Offset j -> StringMatcher -> m ()
151writeMatcher c o sm = do
152 -- handled elsewhere: const char *name; <- smName :: String
153 writeAtByte c (o +. #{off xd3_smatcher, string_match }) (smStringMatch sm)
154 writeAtByte c (o +. #{off xd3_smatcher, large_look }) (smLargeLook sm)
155 writeAtByte c (o +. #{off xd3_smatcher, large_step }) (smLargeStep sm)
156 writeAtByte c (o +. #{off xd3_smatcher, small_look }) (smSmallLook sm)
157 writeAtByte c (o +. #{off xd3_smatcher, small_chain }) (smSmallChain sm)
158 writeAtByte c (o +. #{off xd3_smatcher, small_lchain }) (smSmallLchain sm)
159 writeAtByte c (o +. #{off xd3_smatcher, max_lazy }) (smMaxLazy sm)
160 writeAtByte c (o +. #{off xd3_smatcher, long_enough }) (smLongEnough sm)
161
162packConfig :: PrimMonad m => CString -- ^ Name of software matcher or nullPtr.
163 -> Config
164 -> m ByteArray
165packConfig nptr cfg = do
166 c <- newPinnedByteArray #const sizeof(xd3_config)
167 fillByteArray c 0 #{const sizeof(xd3_config)} 0
168 writeAtByte c #{off xd3_config, winsize} (winsize cfg)
169 writeAtByte c #{off xd3_config, sprevsz} (sprevsz cfg)
170 writeAtByte c #{off xd3_config, iopt_size} (iopt_size cfg)
171 writeAtByte c #{off xd3_config, flags} (coerce (flags cfg) :: Word32)
172 writeCompressorConfig c #{off xd3_config, sec_data} (sec_data cfg)
173 writeCompressorConfig c #{off xd3_config, sec_inst} (sec_inst cfg)
174 writeCompressorConfig c #{off xd3_config, sec_addr} (sec_addr cfg)
175 let msel :: #type xd3_smatch_cfg
176 msel = either (const #{const XD3_SMATCH_SOFT})
177 (fromIntegral . fromEnum)
178 (smatch_cfg cfg)
179 writeAtByte c (#{off xd3_config, smatch_cfg}) msel
180 let mmatcher = either Just (const Nothing) $ smatch_cfg cfg
181 forM_ mmatcher $ \matcher -> do
182 let o = #off xd3_config,smatcher_soft
183 writeAtByte c (o +. (#{off xd3_smatcher, name})) nptr
184 writeMatcher c o matcher
185 unsafeFreezeByteArray c
186
187foreign import ccall "xdelta3.h xd3_config_stream" xd3_config_stream :: Ptr Xd3Stream -> Ptr Config -> IO ErrorCode
188
189foreign import ccall "xdelta3.h xd3_free_stream" xd3_free_stream :: Ptr Xd3Stream -> IO ()
190
191foreign import ccall "xdelta3.h xd3_abort_stream" xd3_abort_stream :: Ptr Xd3Stream -> IO ()
192
193foreign import ccall "xdelta3.h xd3_close_stream" xd3_close_stream :: Ptr Xd3Stream -> IO ErrorCode
194
195
196foreign import ccall "xdelta3.h xd3_decode_input" xd3_decode_input :: Ptr Xd3Stream -> IO ErrorCode
197foreign import ccall "xdelta3.h xd3_encode_input" xd3_encode_input :: Ptr Xd3Stream -> IO ErrorCode
198
199
200foreign import ccall "xdelta3.h xd3_set_source" xd3_set_source :: Ptr Xd3Stream -> Ptr Xd3Source -> IO ErrorCode
201
202