1{-# LANGUAGE BangPatterns, CPP, Rank2Types #-}
4-- Module : Data.Text.Internal.Encoding.Fusion
5-- Copyright : (c) Tom Harper 2008-2009,
6-- (c) Bryan O'Sullivan 2009,
7-- (c) Duncan Coutts 2009
10-- Maintainer : bos@serpentine.com
11-- Stability : experimental
12-- Portability : portable
14-- /Warning/: this is an internal module, and does not have a stable
15-- API or name. Functions in this module may not check or enforce
16-- preconditions expected by public modules. Use at your own risk!
18-- Fusible 'Stream'-oriented functions for converting between 'Text'
19-- and several common encodings.
21module Data.Text.Internal.Encoding.Fusion
34 , module Data.Text.Internal.Encoding.Fusion.Common
38import Control.Exception (assert)
40import Data.ByteString.Internal (ByteString(..), mallocByteString, memcpy)
41import Data.Text.Internal.Fusion (Step(..), Stream(..))
42import Data.Text.Internal.Fusion.Size
43import Data.Text.Encoding.Error
44import Data.Text.Internal.Encoding.Fusion.Common
45import Data.Text.Internal.Unsafe.Char (unsafeChr, unsafeChr8, unsafeChr32)
46import Data.Text.Internal.Unsafe.Shift (shiftL, shiftR)
47import Data.Word (Word8, Word16, Word32)
48import Foreign.ForeignPtr (withForeignPtr, ForeignPtr)
49import Foreign.Storable (pokeByteOff)
50import qualified Data.ByteString as B
51import qualified Data.ByteString.Unsafe as B
52import qualified Data.Text.Internal.Encoding.Utf8 as U8
53import qualified Data.Text.Internal.Encoding.Utf16 as U16
54import qualified Data.Text.Internal.Encoding.Utf32 as U32
55import Data.Text.Unsafe (unsafeDupablePerformIO)
57streamASCII :: ByteString -> Stream Char
58streamASCII bs = Stream next 0 (maxSize l)
64 | otherwise = Yield (unsafeChr8 x1) (i+1)
66 x1 = B.unsafeIndex bs i
67{-# DEPRECATED streamASCII "Do not use this function" #-}
68{-# INLINE [0] streamASCII #-}
70-- | /O(n)/ Convert a 'ByteString' into a 'Stream Char', using UTF-8
72streamUtf8 :: OnDecodeError -> ByteString -> Stream Char
73streamUtf8 onErr bs = Stream next 0 (maxSize l)
78 | U8.validate1 x1 = Yield (unsafeChr8 x1) (i+1)
79 | i+1 < l && U8.validate2 x1 x2 = Yield (U8.chr2 x1 x2) (i+2)
80 | i+2 < l && U8.validate3 x1 x2 x3 = Yield (U8.chr3 x1 x2 x3) (i+3)
81 | i+3 < l && U8.validate4 x1 x2 x3 x4 = Yield (U8.chr4 x1 x2 x3 x4) (i+4)
82 | otherwise = decodeError "streamUtf8" "UTF-8" onErr (Just x1) (i+1)
88 idx = B.unsafeIndex bs
89{-# INLINE [0] streamUtf8 #-}
91-- | /O(n)/ Convert a 'ByteString' into a 'Stream Char', using little
92-- endian UTF-16 encoding.
93streamUtf16LE :: OnDecodeError -> ByteString -> Stream Char
94streamUtf16LE onErr bs = Stream next 0 (maxSize (l `shiftR` 1))
100 | i+1 < l && U16.validate1 x1 = Yield (unsafeChr x1) (i+2)
101 | i+3 < l && U16.validate2 x1 x2 = Yield (U16.chr2 x1 x2) (i+4)
102 | otherwise = decodeError "streamUtf16LE" "UTF-16LE" onErr Nothing (i+1)
104 x1 = idx i + (idx (i + 1) `shiftL` 8)
105 x2 = idx (i + 2) + (idx (i + 3) `shiftL` 8)
106 idx = fromIntegral . B.unsafeIndex bs :: Int -> Word16
107{-# INLINE [0] streamUtf16LE #-}
109-- | /O(n)/ Convert a 'ByteString' into a 'Stream Char', using big
110-- endian UTF-16 encoding.
111streamUtf16BE :: OnDecodeError -> ByteString -> Stream Char
112streamUtf16BE onErr bs = Stream next 0 (maxSize (l `shiftR` 1))
118 | i+1 < l && U16.validate1 x1 = Yield (unsafeChr x1) (i+2)
119 | i+3 < l && U16.validate2 x1 x2 = Yield (U16.chr2 x1 x2) (i+4)
120 | otherwise = decodeError "streamUtf16BE" "UTF-16BE" onErr Nothing (i+1)
122 x1 = (idx i `shiftL` 8) + idx (i + 1)
123 x2 = (idx (i + 2) `shiftL` 8) + idx (i + 3)
124 idx = fromIntegral . B.unsafeIndex bs :: Int -> Word16
125{-# INLINE [0] streamUtf16BE #-}
127-- | /O(n)/ Convert a 'ByteString' into a 'Stream Char', using big
128-- endian UTF-32 encoding.
129streamUtf32BE :: OnDecodeError -> ByteString -> Stream Char
130streamUtf32BE onErr bs = Stream next 0 (maxSize (l `shiftR` 2))
136 | i+3 < l && U32.validate x = Yield (unsafeChr32 x) (i+4)
137 | otherwise = decodeError "streamUtf32BE" "UTF-32BE" onErr Nothing (i+1)
139 x = shiftL x1 24 + shiftL x2 16 + shiftL x3 8 + x4
144 idx = fromIntegral . B.unsafeIndex bs :: Int -> Word32
145{-# INLINE [0] streamUtf32BE #-}
147-- | /O(n)/ Convert a 'ByteString' into a 'Stream Char', using little
148-- endian UTF-32 encoding.
149streamUtf32LE :: OnDecodeError -> ByteString -> Stream Char
150streamUtf32LE onErr bs = Stream next 0 (maxSize (l `shiftR` 2))
156 | i+3 < l && U32.validate x = Yield (unsafeChr32 x) (i+4)
157 | otherwise = decodeError "streamUtf32LE" "UTF-32LE" onErr Nothing (i+1)
159 x = shiftL x4 24 + shiftL x3 16 + shiftL x2 8 + x1
164 idx = fromIntegral . B.unsafeIndex bs :: Int -> Word32
165{-# INLINE [0] streamUtf32LE #-}
167-- | /O(n)/ Convert a 'Stream' 'Word8' to a 'ByteString'.
168unstream :: Stream Word8 -> ByteString
169unstream (Stream next s0 len) = unsafeDupablePerformIO $ do
170 let mlen = upperBound 4 len
171 mallocByteString mlen >>= loop mlen 0 s0
173 loop !n !off !s fp = case next s of
174 Done -> trimUp fp n off
175 Skip s' -> loop n off s' fp
177 | off == n -> realloc fp n off s' x
179 withForeignPtr fp $ \p -> pokeByteOff p off x
181 {-# NOINLINE realloc #-}
182 realloc fp n off s x = do
185 withForeignPtr fp' $ \p -> pokeByteOff p off x
186 loop n' (off+1) s fp'
187 {-# NOINLINE trimUp #-}
188 trimUp fp _ off = return $! PS fp 0 off
189 copy0 :: ForeignPtr Word8 -> Int -> Int -> IO (ForeignPtr Word8)
190 copy0 !src !srcLen !destLen =
192 assert (srcLen <= destLen) $
195 dest <- mallocByteString destLen
196 withForeignPtr src $ \src' ->
197 withForeignPtr dest $ \dest' ->
198 memcpy dest' src' (fromIntegral srcLen)
201decodeError :: forall s. String -> String -> OnDecodeError -> Maybe Word8
203decodeError func kind onErr mb i =
204 case onErr desc mb of
207 where desc = "Data.Text.Internal.Encoding.Fusion." ++ func ++ ": Invalid " ++
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