diff options
author | Joe Crayne <joe@jerkface.net> | 2018-10-27 16:26:10 -0400 |
---|---|---|
committer | Joe Crayne <joe@jerkface.net> | 2018-10-27 16:26:10 -0400 |
commit | 4aab5a236e578f3cd97566bc142027e06e955f73 (patch) | |
tree | 9aeba26a693c8d17dfc66d6d98b2209a0be6b8b6 /haskell/Data/VCDIFF/XDelta.hsc | |
parent | 2d01ddf9bffb7be441e2cf1c7071240148839ab5 (diff) |
build fix
Diffstat (limited to 'haskell/Data/VCDIFF/XDelta.hsc')
-rw-r--r-- | haskell/Data/VCDIFF/XDelta.hsc | 202 |
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 #-} | ||
5 | module Data.VCDIFF.XDelta where | ||
6 | |||
7 | import Control.Monad | ||
8 | import Control.Monad.Primitive | ||
9 | import Data.Bits | ||
10 | import qualified Data.ByteString as B | ||
11 | import Data.Coerce | ||
12 | import Data.Int | ||
13 | import Data.Primitive.ByteArray | ||
14 | import Data.Primitive.ByteArray.Util | ||
15 | import qualified Data.Text as T | ||
16 | import Data.Text.Encoding | ||
17 | import Data.VCDIFF.Types | ||
18 | import Data.Word | ||
19 | import Foreign.C.Types | ||
20 | import Foreign.C.String | ||
21 | import 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 | |||
34 | type instance SizeOf Usize_t = #const sizeof(usize_t) | ||
35 | type instance SizeOf (FunPtr a) = #const sizeof(void(*)()) | ||
36 | type instance SizeOf (Ptr a) = #const sizeof(void*) | ||
37 | type instance SizeOf #{type int} = #const sizeof(int) | ||
38 | type instance SizeOf #{type unsigned int} = #const sizeof(unsigned int) | ||
39 | |||
40 | |||
41 | data Xd3Source | ||
42 | |||
43 | newtype Source m = Source (MutableByteArray (PrimState m)) | ||
44 | |||
45 | newSource :: 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) | ||
51 | newSource 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 | |||
61 | sourcePtr :: Source m -> Ptr Xd3Source | ||
62 | sourcePtr (Source src) = ptr (mutableByteArrayContents src) | ||
63 | |||
64 | sourceRequestedBlocknumber :: PrimMonad m => Source m -> m Xoff_t | ||
65 | sourceRequestedBlocknumber (Source src) = readAtByte src (#{off xd3_source, getblkno}) | ||
66 | |||
67 | data 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 | |||
73 | sourceWriteCurrentBlock :: PrimMonad m => Source m -> CurrentBlock -> m () | ||
74 | sourceWriteCurrentBlock (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 | |||
79 | sourceWriteEOFKnown :: PrimMonad m => Source m -> Bool -> m () | ||
80 | sourceWriteEOFKnown (Source src) False = writeAtByte src (#{off xd3_source, eof_known}) (0 :: #{type int}) | ||
81 | sourceWriteEOFKnown (Source src) True = writeAtByte src (#{off xd3_source, eof_known}) (1 :: #{type int}) | ||
82 | |||
83 | newtype StreamArray m = StreamArray (MutableByteArray (PrimState m)) | ||
84 | |||
85 | newStreamArray :: PrimMonad m => | ||
86 | Maybe String -> m (StreamArray m, CString) | ||
87 | newStreamArray 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 | |||
100 | streamArrayPtr :: StreamArray m -> Ptr Xd3Stream | ||
101 | streamArrayPtr (StreamArray s) = ptr (mutableByteArrayContents s) | ||
102 | |||
103 | setFlag :: PrimMonad m => Flags -> StreamArray m -> Bool -> m () | ||
104 | setFlag 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 | |||
111 | setFlush :: PrimMonad m => StreamArray m -> Bool -> m () | ||
112 | setFlush = setFlag XD3_FLUSH | ||
113 | |||
114 | setSkipWindow :: PrimMonad m => StreamArray m -> Bool -> m () | ||
115 | setSkipWindow = setFlag XD3_SKIP_WINDOW | ||
116 | |||
117 | |||
118 | avail_input :: PrimMonad m => StreamArray m -> Ptr a -> Usize_t -> m () | ||
119 | avail_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 | |||
124 | nextOut :: PrimMonad m => StreamArray m -> ((Ptr Word8, Usize_t) -> m a) -> m a | ||
125 | nextOut (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. | ||
137 | errorString :: PrimMonad m => StreamArray m -> m String | ||
138 | errorString (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 | |||
144 | writeCompressorConfig :: (PrimMonad m, _) => MutableByteArray (PrimState m) -> Offset j -> CompressorConfig -> m () | ||
145 | writeCompressorConfig 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 | |||
150 | writeMatcher :: (PrimMonad m, _) => MutableByteArray (PrimState m) -> Offset j -> StringMatcher -> m () | ||
151 | writeMatcher 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 | |||
162 | packConfig :: PrimMonad m => CString -- ^ Name of software matcher or nullPtr. | ||
163 | -> Config | ||
164 | -> m ByteArray | ||
165 | packConfig 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 | |||
187 | foreign import ccall "xdelta3.h xd3_config_stream" xd3_config_stream :: Ptr Xd3Stream -> Ptr Config -> IO ErrorCode | ||
188 | |||
189 | foreign import ccall "xdelta3.h xd3_free_stream" xd3_free_stream :: Ptr Xd3Stream -> IO () | ||
190 | |||
191 | foreign import ccall "xdelta3.h xd3_abort_stream" xd3_abort_stream :: Ptr Xd3Stream -> IO () | ||
192 | |||
193 | foreign import ccall "xdelta3.h xd3_close_stream" xd3_close_stream :: Ptr Xd3Stream -> IO ErrorCode | ||
194 | |||
195 | |||
196 | foreign import ccall "xdelta3.h xd3_decode_input" xd3_decode_input :: Ptr Xd3Stream -> IO ErrorCode | ||
197 | foreign import ccall "xdelta3.h xd3_encode_input" xd3_encode_input :: Ptr Xd3Stream -> IO ErrorCode | ||
198 | |||
199 | |||
200 | foreign import ccall "xdelta3.h xd3_set_source" xd3_set_source :: Ptr Xd3Stream -> Ptr Xd3Source -> IO ErrorCode | ||
201 | |||
202 | |||