1{-# LANGUAGE BangPatterns #-}
4-- Module : Data.Text.Encoding
5-- Copyright : (c) Tom Harper 2008-2009,
6-- (c) Bryan O'Sullivan 2009,
7-- (c) Duncan Coutts 2009
10-- Maintainer : rtharper@aftereternity.co.uk, bos@serpentine.com,
12-- Stability : experimental
13-- Portability : portable
15-- Fusible 'Stream'-oriented functions for converting between 'Text'
16-- and several common encodings.
18module Data.Text.Encoding.Fusion
32 -- Restreaming is the act of converting from one 'Stream'
33 -- representation to another.
42import Control.Exception (assert)
43import Data.Bits (shiftL, shiftR, (.&.))
44import Data.ByteString as B
45import Data.ByteString.Internal (ByteString(..), mallocByteString, memcpy)
47import Data.Text.Fusion (Step(..), Stream(..))
48import Data.Text.UnsafeChar (unsafeChr, unsafeChr8, unsafeChr32)
49import Data.Word (Word8, Word16, Word32)
50import Foreign.ForeignPtr (withForeignPtr, ForeignPtr)
51import Foreign.Storable (pokeByteOff)
52import System.IO.Unsafe (unsafePerformIO)
53import qualified Data.ByteString as B
54import qualified Data.ByteString.Unsafe as B
55import qualified Data.Text.Utf16 as U16
56import qualified Data.Text.Utf32 as U32
57import qualified Data.Text.Utf8 as U8
59data T4 a b c d = T4 !a !b !c !d
61streamASCII :: ByteString -> Stream Char
62streamASCII bs = Stream next 0 l
68 | otherwise = Yield (unsafeChr8 x1) (i+1)
70 x1 = B.unsafeIndex bs i
71{-# INLINE [0] streamASCII #-}
73-- | /O(n) Convert a ByteString into a Stream Char, using the specified encoding standard.
74streamUtf8 :: ByteString -> Stream Char
75streamUtf8 bs = Stream next 0 l
81 | U8.validate1 x1 = Yield (unsafeChr8 x1) (i+1)
82 | i+1 < l && U8.validate2 x1 x2 = Yield (U8.chr2 x1 x2) (i+2)
83 | i+2 < l && U8.validate3 x1 x2 x3 = Yield (U8.chr3 x1 x2 x3) (i+3)
84 | i+3 < l && U8.validate4 x1 x2 x3 x4 = Yield (U8.chr4 x1 x2 x3 x4) (i+4)
85 | otherwise = error "bsStream: bad UTF-8 stream"
91 idx = B.unsafeIndex bs
92{-# INLINE [0] streamUtf8 #-}
94streamUtf16LE :: ByteString -> Stream Char
95streamUtf16LE bs = Stream next 0 l
101 | i+1 < l && U16.validate1 x1 = Yield (unsafeChr x1) (i+2)
102 | i+3 < l && U16.validate2 x1 x2 = Yield (U16.chr2 x1 x2) (i+4)
103 | otherwise = error $ "bsStream: bad UTF-16LE stream"
105 x1 = (shiftL (idx (i + 1)) 8) + (idx i)
106 x2 = (shiftL (idx (i + 3)) 8) + (idx (i + 2))
107 idx = fromIntegral . B.unsafeIndex bs :: Int -> Word16
108{-# INLINE [0] streamUtf16LE #-}
110streamUtf16BE :: ByteString -> Stream Char
111streamUtf16BE bs = Stream next 0 l
117 | i+1 < l && U16.validate1 x1 = Yield (unsafeChr x1) (i+2)
118 | i+3 < l && U16.validate2 x1 x2 = Yield (U16.chr2 x1 x2) (i+4)
119 | otherwise = error $ "bsStream: bad UTF16-BE stream "
121 x1 = (shiftL (idx i) 8) + (idx (i + 1))
122 x2 = (shiftL (idx (i + 2)) 8) + (idx (i + 3))
123 idx = fromIntegral . B.unsafeIndex bs :: Int -> Word16
124{-# INLINE [0] streamUtf16BE #-}
126streamUtf32BE :: ByteString -> Stream Char
127streamUtf32BE bs = Stream next 0 l
133 | i+3 < l && U32.validate x = Yield (unsafeChr32 x) (i+4)
134 | otherwise = error "bsStream: bad UTF-32BE stream"
136 x = shiftL x1 24 + shiftL x2 16 + shiftL x3 8 + x4
141 idx = fromIntegral . B.unsafeIndex bs :: Int -> Word32
142{-# INLINE [0] streamUtf32BE #-}
144streamUtf32LE :: ByteString -> Stream Char
145streamUtf32LE bs = Stream next 0 l
151 | i+3 < l && U32.validate x = Yield (unsafeChr32 x) (i+4)
152 | otherwise = error "bsStream: bad UTF-32LE stream"
154 x = shiftL x4 24 + shiftL x3 16 + shiftL x2 8 + x1
159 idx = fromIntegral . B.unsafeIndex bs :: Int -> Word32
160{-# INLINE [0] streamUtf32LE #-}
162restreamASCII :: Stream Char -> Stream Word8
163restreamASCII (Stream next0 s0 len) = Stream next s0 (len*2)
165 next !s = case next0 s of
168 Yield x xs -> Yield x' xs
169 where x' = fromIntegral (ord x) :: Word8
170{-# INLINE restreamASCII #-}
172-- | /O(n)/ Convert a Stream Char into a UTF-8 encoded Stream Word8.
173restreamUtf8 :: Stream Char -> Stream Word8
174restreamUtf8 (Stream next0 s0 len) =
175 Stream next (T4 (Just s0) Nothing Nothing Nothing) (len*2)
178 next (T4 (Just s) Nothing Nothing Nothing) = case next0 s of
180 Skip s' -> Skip (T4 (Just s') Nothing Nothing Nothing)
182 | n <= 0x7F -> Yield c (T4 (Just xs) Nothing Nothing Nothing)
183 | n <= 0x07FF -> Yield (fst c2) (T4 (Just xs) (Just $ snd c2) Nothing Nothing)
184 | n <= 0xFFFF -> Yield (fst3 c3) (T4 (Just xs) (Just $ snd3 c3) (Just $ trd3 c3) Nothing)
185 | otherwise -> Yield (fst4 c4) (T4 (Just xs) (Just $ snd4 c4) (Just $ trd4 c4) (Just $ fth4 c4))
199 next (T4 (Just s) (Just x2) Nothing Nothing) = Yield x2 (T4 (Just s) Nothing Nothing Nothing)
200 next (T4 (Just s) (Just x2) x3 Nothing) = Yield x2 (T4 (Just s) x3 Nothing Nothing)
201 next (T4 (Just s) (Just x2) x3 x4) = Yield x2 (T4 (Just s) x3 x4 Nothing)
202 next _ = internalError "restreamUtf8"
203{-# INLINE restreamUtf8 #-}
205restreamUtf16BE :: Stream Char -> Stream Word8
206restreamUtf16BE (Stream next0 s0 len) =
207 Stream next (T4 (Just s0) Nothing Nothing Nothing) (len*2)
210 next (T4 (Just s) Nothing Nothing Nothing) = case next0 s of
212 Skip s' -> Skip (T4 (Just s') Nothing Nothing Nothing)
214 | n < 0x10000 -> Yield (fromIntegral $ shiftR n 8) (T4 (Just xs) (Just (fromIntegral n)) Nothing Nothing)
215 | otherwise -> Yield c1 (T4 (Just xs) (Just c2) (Just c3) (Just c4))
219 c1 = fromIntegral (shiftR n1 18 + 0xD8)
220 c2 = fromIntegral (shiftR n1 10)
222 c3 = fromIntegral (shiftR n2 8 + 0xDC)
224 next (T4 (Just s) (Just x2) Nothing Nothing) = Yield x2 (T4 (Just s) Nothing Nothing Nothing)
225 next (T4 (Just s) (Just x2) x3 Nothing) = Yield x2 (T4 (Just s) x3 Nothing Nothing)
226 next (T4 (Just s) (Just x2) x3 x4) = Yield x2 (T4 (Just s) x3 x4 Nothing)
227 next _ = internalError "restreamUtf16BE"
228{-# INLINE restreamUtf16BE #-}
230restreamUtf16LE :: Stream Char -> Stream Word8
231restreamUtf16LE (Stream next0 s0 len) =
232 Stream next (T4 (Just s0) Nothing Nothing Nothing) (len*2)
235 next (T4 (Just s) Nothing Nothing Nothing) = case next0 s of
237 Skip s' -> Skip (T4 (Just s') Nothing Nothing Nothing)
239 | n < 0x10000 -> Yield (fromIntegral n) (T4 (Just xs) (Just (fromIntegral $ shiftR n 8)) Nothing Nothing)
240 | otherwise -> Yield c1 (T4 (Just xs) (Just c2) (Just c3) (Just c4))
244 c2 = fromIntegral (shiftR n1 18 + 0xD8)
245 c1 = fromIntegral (shiftR n1 10)
247 c4 = fromIntegral (shiftR n2 8 + 0xDC)
249 next (T4 (Just s) (Just x2) Nothing Nothing) = Yield x2 (T4 (Just s) Nothing Nothing Nothing)
250 next (T4 (Just s) (Just x2) x3 Nothing) = Yield x2 (T4 (Just s) x3 Nothing Nothing)
251 next (T4 (Just s) (Just x2) x3 x4) = Yield x2 (T4 (Just s) x3 x4 Nothing)
252 next _ = internalError "restreamUtf16LE"
253{-# INLINE restreamUtf16LE #-}
255restreamUtf32BE :: Stream Char -> Stream Word8
256restreamUtf32BE (Stream next0 s0 len) =
257 Stream next (T4 (Just s0) Nothing Nothing Nothing) (len*2)
260 next (T4 (Just s) Nothing Nothing Nothing) = case next0 s of
262 Skip s' -> Skip (T4 (Just s') Nothing Nothing Nothing)
263 Yield x xs -> Yield c1 (T4 (Just xs) (Just c2) (Just c3) (Just c4))
266 c1 = fromIntegral $ shiftR n 24
267 c2 = fromIntegral $ shiftR n 16
268 c3 = fromIntegral $ shiftR n 8
270 next (T4 (Just s) (Just x2) Nothing Nothing) = Yield x2 (T4 (Just s) Nothing Nothing Nothing)
271 next (T4 (Just s) (Just x2) x3 Nothing) = Yield x2 (T4 (Just s) x3 Nothing Nothing)
272 next (T4 (Just s) (Just x2) x3 x4) = Yield x2 (T4 (Just s) x3 x4 Nothing)
273 next _ = internalError "restreamUtf32BE"
274{-# INLINE restreamUtf32BE #-}
276restreamUtf32LE :: Stream Char -> Stream Word8
277restreamUtf32LE (Stream next0 s0 len) =
278 Stream next (T4 (Just s0) Nothing Nothing Nothing) (len*2)
281 next (T4 (Just s) Nothing Nothing Nothing) = case next0 s of
283 Skip s' -> Skip (T4 (Just s') Nothing Nothing Nothing)
284 Yield x xs -> Yield c1 (T4 (Just xs) (Just c2) (Just c3) (Just c4))
287 c4 = fromIntegral $ shiftR n 24
288 c3 = fromIntegral $ shiftR n 16
289 c2 = fromIntegral $ shiftR n 8
291 next (T4 (Just s) (Just x2) Nothing Nothing) = Yield x2 (T4 (Just s) Nothing Nothing Nothing)
292 next (T4 (Just s) (Just x2) x3 Nothing) = Yield x2 (T4 (Just s) x3 Nothing Nothing)
293 next (T4 (Just s) (Just x2) x3 x4) = Yield x2 (T4 (Just s) x3 x4 Nothing)
294 next _ = internalError "restreamUtf32LE"
295{-# INLINE restreamUtf32LE #-}
298-- | /O(n)/ Convert a 'Stream' 'Word8' to a 'ByteString'.
299unstream :: Stream Word8 -> ByteString
300unstream (Stream next s0 len) = unsafePerformIO $ do
301 fp0 <- mallocByteString len
304 loop !fp !n !off !s = case next s of
305 Done -> trimUp fp n off
306 Skip s' -> loop fp n off s'
308 | n == off -> realloc fp n off s' x
310 withForeignPtr fp $ \p -> pokeByteOff p off x
312 {-# NOINLINE realloc #-}
313 realloc fp n off s x = do
316 withForeignPtr fp' $ \p -> pokeByteOff p off x
317 loop fp' n' (off+1) s
318 {-# NOINLINE trimUp #-}
319 trimUp fp _ off = return $! PS fp 0 off
320 copy0 :: ForeignPtr Word8 -> Int -> Int -> IO (ForeignPtr Word8)
321 copy0 !src !srcLen !destLen = assert (srcLen <= destLen) $ do
322 dest <- mallocByteString destLen
323 withForeignPtr src $ \src' ->
324 withForeignPtr dest $ \dest' ->
325 memcpy dest' src' (fromIntegral destLen)
328internalError :: String -> a
330 error $ "Data.Text.Encoding.Fusion." ++ func ++ ": internal error"
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list