{-# LANGUAGE CPP #-}
module Darcs.Util.ByteString
(
gzReadFilePS
, mmapFilePS
, gzWriteFilePS
, gzWriteFilePSs
, gzReadStdin
, gzWriteHandle
, FileSegment
, readSegment
, isGZFile
, gzDecompress
, dropSpace
, linesPS
, unlinesPS
, hashPS
, breakFirstPS
, breakLastPS
, substrPS
, isFunky
, fromHex2PS
, fromPS2Hex
, betweenLinesPS
, intercalate
, isAscii
, decodeLocale
, encodeLocale
, unpackPSFromUTF8
, packStringToUTF8
, prop_unlinesPS_linesPS_left_inverse
, prop_linesPS_length
, prop_unlinesPS_length
, propHexConversion
, spec_betweenLinesPS
) where
import Darcs.Prelude
import qualified Data.ByteString as B
import qualified Data.ByteString.Char8 as BC
import qualified Data.ByteString.Lazy as BL
import Data.ByteString (intercalate)
import qualified Data.ByteString.Base16 as B16
import System.IO ( withFile, IOMode(ReadMode)
, hSeek, SeekMode(SeekFromEnd,AbsoluteSeek)
, openBinaryFile, hClose, Handle, hGetChar
, stdin)
import System.IO.Error ( catchIOError )
import System.IO.Unsafe ( unsafePerformIO )
import Data.Bits ( rotateL )
import Data.Char ( ord )
import Data.Word ( Word8 )
import Data.Int ( Int32, Int64 )
import Data.List ( intersperse )
import Control.Exception ( throw )
import Control.Monad ( when )
import Control.Monad.ST.Lazy ( ST )
import qualified Codec.Compression.GZip as GZ
import qualified Codec.Compression.Zlib.Internal as ZI
import Darcs.Util.Encoding ( decode, encode, decodeUtf8, encodeUtf8 )
import Darcs.Util.Global ( addCRCWarning )
#if mingw32_HOST_OS
#else
import System.IO.MMap( mmapFileByteString )
#endif
import System.Mem( performGC )
import System.Posix.Files( fileSize, getSymbolicLinkStatus )
isSpaceWord8 :: Word8 -> Bool
isSpaceWord8 :: Word8 -> Bool
isSpaceWord8 Word8
0x20 = Bool
True
isSpaceWord8 Word8
0x09 = Bool
True
isSpaceWord8 Word8
0x0A = Bool
True
isSpaceWord8 Word8
0x0D = Bool
True
isSpaceWord8 Word8
_ = Bool
False
{-# INLINE isSpaceWord8 #-}
dropSpace :: B.ByteString -> B.ByteString
dropSpace :: ByteString -> ByteString
dropSpace ByteString
bs = (Word8 -> Bool) -> ByteString -> ByteString
B.dropWhile Word8 -> Bool
isSpaceWord8 ByteString
bs
{-# INLINE isFunky #-}
isFunky :: B.ByteString -> Bool
isFunky :: ByteString -> Bool
isFunky ByteString
ps = Word8
0 Word8 -> ByteString -> Bool
`B.elem` ByteString
ps Bool -> Bool -> Bool
|| Word8
26 Word8 -> ByteString -> Bool
`B.elem` ByteString
ps
{-# INLINE hashPS #-}
hashPS :: B.ByteString -> Int32
hashPS :: ByteString -> Int32
hashPS = forall a. (a -> Word8 -> a) -> a -> ByteString -> a
B.foldl' Int32 -> Word8 -> Int32
hashByte Int32
0
{-# INLINE hashByte #-}
hashByte :: Int32 -> Word8 -> Int32
hashByte :: Int32 -> Word8 -> Int32
hashByte Int32
h Word8
x = forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
x forall a. Num a => a -> a -> a
+ forall a. Bits a => a -> Int -> a
rotateL Int32
h Int
8
{-# INLINE substrPS #-}
substrPS :: B.ByteString -> B.ByteString -> Maybe Int
substrPS :: ByteString -> ByteString -> Maybe Int
substrPS ByteString
tok ByteString
str
| ByteString -> Bool
B.null ByteString
tok = forall a. a -> Maybe a
Just Int
0
| ByteString -> Int
B.length ByteString
tok forall a. Ord a => a -> a -> Bool
> ByteString -> Int
B.length ByteString
str = forall a. Maybe a
Nothing
| Bool
otherwise = do Int
n <- Word8 -> ByteString -> Maybe Int
B.elemIndex (HasCallStack => ByteString -> Word8
B.head ByteString
tok) ByteString
str
let ttok :: ByteString
ttok = HasCallStack => ByteString -> ByteString
B.tail ByteString
tok
reststr :: ByteString
reststr = Int -> ByteString -> ByteString
B.drop (Int
nforall a. Num a => a -> a -> a
+Int
1) ByteString
str
if ByteString
ttok forall a. Eq a => a -> a -> Bool
== Int -> ByteString -> ByteString
B.take (ByteString -> Int
B.length ByteString
ttok) ByteString
reststr
then forall a. a -> Maybe a
Just Int
n
else ((Int
nforall a. Num a => a -> a -> a
+Int
1)forall a. Num a => a -> a -> a
+) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` ByteString -> ByteString -> Maybe Int
substrPS ByteString
tok ByteString
reststr
{-# INLINE breakFirstPS #-}
breakFirstPS :: Char -> B.ByteString -> Maybe (B.ByteString,B.ByteString)
breakFirstPS :: Char -> ByteString -> Maybe (ByteString, ByteString)
breakFirstPS Char
c ByteString
p = case Char -> ByteString -> Maybe Int
BC.elemIndex Char
c ByteString
p of
Maybe Int
Nothing -> forall a. Maybe a
Nothing
Just Int
n -> forall a. a -> Maybe a
Just (Int -> ByteString -> ByteString
B.take Int
n ByteString
p, Int -> ByteString -> ByteString
B.drop (Int
nforall a. Num a => a -> a -> a
+Int
1) ByteString
p)
{-# INLINE breakLastPS #-}
breakLastPS :: Char -> B.ByteString -> Maybe (B.ByteString,B.ByteString)
breakLastPS :: Char -> ByteString -> Maybe (ByteString, ByteString)
breakLastPS Char
c ByteString
p = case Char -> ByteString -> Maybe Int
BC.elemIndexEnd Char
c ByteString
p of
Maybe Int
Nothing -> forall a. Maybe a
Nothing
Just Int
n -> forall a. a -> Maybe a
Just (Int -> ByteString -> ByteString
B.take Int
n ByteString
p, Int -> ByteString -> ByteString
B.drop (Int
nforall a. Num a => a -> a -> a
+Int
1) ByteString
p)
{-# INLINE linesPS #-}
linesPS :: B.ByteString -> [B.ByteString]
linesPS :: ByteString -> [ByteString]
linesPS ByteString
ps
| ByteString -> Bool
B.null ByteString
ps = [ByteString
B.empty]
| Bool
otherwise = Char -> ByteString -> [ByteString]
BC.split Char
'\n' ByteString
ps
{-# INLINE unlinesPS #-}
unlinesPS :: [B.ByteString] -> B.ByteString
unlinesPS :: [ByteString] -> ByteString
unlinesPS [] = ByteString
B.empty
unlinesPS [ByteString]
x = [ByteString] -> ByteString
B.concat forall a b. (a -> b) -> a -> b
$ forall a. a -> [a] -> [a]
intersperse (Char -> ByteString
BC.singleton Char
'\n') [ByteString]
x
prop_unlinesPS_linesPS_left_inverse :: B.ByteString -> Bool
prop_unlinesPS_linesPS_left_inverse :: ByteString -> Bool
prop_unlinesPS_linesPS_left_inverse ByteString
x = [ByteString] -> ByteString
unlinesPS (ByteString -> [ByteString]
linesPS ByteString
x) forall a. Eq a => a -> a -> Bool
== ByteString
x
prop_linesPS_length :: B.ByteString -> Bool
prop_linesPS_length :: ByteString -> Bool
prop_linesPS_length ByteString
x = forall (t :: * -> *) a. Foldable t => t a -> Int
length (ByteString -> [ByteString]
linesPS ByteString
x) forall a. Eq a => a -> a -> Bool
== forall (t :: * -> *) a. Foldable t => t a -> Int
length (Char -> ByteString -> [Int]
BC.elemIndices Char
'\n' ByteString
x) forall a. Num a => a -> a -> a
+ Int
1
prop_unlinesPS_length :: [B.ByteString] -> Bool
prop_unlinesPS_length :: [ByteString] -> Bool
prop_unlinesPS_length [ByteString]
xs =
ByteString -> Int
B.length ([ByteString] -> ByteString
unlinesPS [ByteString]
xs) forall a. Eq a => a -> a -> Bool
== if forall (t :: * -> *) a. Foldable t => t a -> Bool
null [ByteString]
xs then Int
0 else forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum (forall a b. (a -> b) -> [a] -> [b]
map ByteString -> Int
B.length [ByteString]
xs) forall a. Num a => a -> a -> a
+ forall (t :: * -> *) a. Foldable t => t a -> Int
length [ByteString]
xs forall a. Num a => a -> a -> a
- Int
1
gzDecompress :: Maybe Int -> BL.ByteString -> ([B.ByteString], Bool)
gzDecompress :: Maybe Int -> ByteString -> ([ByteString], Bool)
gzDecompress Maybe Int
mbufsize =
(forall s. DecompressStream (ST s))
-> ByteString -> ([ByteString], Bool)
decompressWarn (forall s. Format -> DecompressParams -> DecompressStream (ST s)
ZI.decompressST Format
ZI.gzipFormat DecompressParams
decompressParams)
where
decompressParams :: DecompressParams
decompressParams = case Maybe Int
mbufsize of
Just Int
bufsize -> DecompressParams
GZ.defaultDecompressParams { decompressBufferSize :: Int
GZ.decompressBufferSize = Int
bufsize }
Maybe Int
Nothing -> DecompressParams
GZ.defaultDecompressParams
decompressWarn :: (forall s . ZI.DecompressStream (ST s)) -> BL.ByteString -> ([B.ByteString], Bool)
decompressWarn :: (forall s. DecompressStream (ST s))
-> ByteString -> ([ByteString], Bool)
decompressWarn = forall a.
(ByteString -> a -> a)
-> (ByteString -> a)
-> (DecompressError -> a)
-> (forall s. DecompressStream (ST s))
-> ByteString
-> a
ZI.foldDecompressStreamWithInput
(\ByteString
x ~([ByteString]
xs, Bool
b) -> (ByteString
xforall a. a -> [a] -> [a]
:[ByteString]
xs, Bool
b))
(\ByteString
xs -> if ByteString -> Bool
BL.null ByteString
xs
then ([], Bool
False)
else forall a. HasCallStack => [Char] -> a
error [Char]
"trailing data at end of compressed stream"
)
forall {a}. DecompressError -> ([a], Bool)
handleBad
handleBad :: DecompressError -> ([a], Bool)
handleBad (ZI.DataFormatError [Char]
"incorrect data check") = ([], Bool
True)
handleBad DecompressError
e = forall a. HasCallStack => [Char] -> a
error (forall a. Show a => a -> [Char]
show DecompressError
e)
isGZFile :: FilePath -> IO (Maybe Int)
isGZFile :: [Char] -> IO (Maybe Int)
isGZFile [Char]
f = do
Handle
h <- [Char] -> IOMode -> IO Handle
openBinaryFile [Char]
f IOMode
ReadMode
ByteString
header <- Handle -> Int -> IO ByteString
B.hGet Handle
h Int
2
if ByteString
header forall a. Eq a => a -> a -> Bool
/= [Word8] -> ByteString
B.pack [Word8
31,Word8
139]
then do Handle -> IO ()
hClose Handle
h
forall (m :: * -> *) a. Monad m => a -> m a
return forall a. Maybe a
Nothing
else do Handle -> SeekMode -> Integer -> IO ()
hSeek Handle
h SeekMode
SeekFromEnd (-Integer
4)
Int
len <- Handle -> IO Int
hGetLittleEndInt Handle
h
Handle -> IO ()
hClose Handle
h
forall (m :: * -> *) a. Monad m => a -> m a
return (forall a. a -> Maybe a
Just Int
len)
gzReadFilePS :: FilePath -> IO B.ByteString
gzReadFilePS :: [Char] -> IO ByteString
gzReadFilePS [Char]
f = do
Maybe Int
mlen <- [Char] -> IO (Maybe Int)
isGZFile [Char]
f
case Maybe Int
mlen of
Maybe Int
Nothing -> [Char] -> IO ByteString
mmapFilePS [Char]
f
Just Int
len ->
do
let doDecompress :: ByteString -> IO [ByteString]
doDecompress ByteString
buf = let ([ByteString]
res, Bool
bad) = Maybe Int -> ByteString -> ([ByteString], Bool)
gzDecompress (forall a. a -> Maybe a
Just Int
len) ByteString
buf
in do forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
bad forall a b. (a -> b) -> a -> b
$ [Char] -> IO ()
addCRCWarning [Char]
f
forall (m :: * -> *) a. Monad m => a -> m a
return [ByteString]
res
ByteString
compressed <- ([ByteString] -> ByteString
BL.fromChunks forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) a. Monad m => a -> m a
return) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` [Char] -> IO ByteString
mmapFilePS [Char]
f
[ByteString] -> ByteString
B.concat forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` ByteString -> IO [ByteString]
doDecompress ByteString
compressed
hGetLittleEndInt :: Handle -> IO Int
hGetLittleEndInt :: Handle -> IO Int
hGetLittleEndInt Handle
h = do
Int
b1 <- Char -> Int
ord forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` Handle -> IO Char
hGetChar Handle
h
Int
b2 <- Char -> Int
ord forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` Handle -> IO Char
hGetChar Handle
h
Int
b3 <- Char -> Int
ord forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` Handle -> IO Char
hGetChar Handle
h
Int
b4 <- Char -> Int
ord forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` Handle -> IO Char
hGetChar Handle
h
forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ Int
b1 forall a. Num a => a -> a -> a
+ Int
256forall a. Num a => a -> a -> a
*Int
b2 forall a. Num a => a -> a -> a
+ Int
65536forall a. Num a => a -> a -> a
*Int
b3 forall a. Num a => a -> a -> a
+ Int
16777216forall a. Num a => a -> a -> a
*Int
b4
gzWriteFilePS :: FilePath -> B.ByteString -> IO ()
gzWriteFilePS :: [Char] -> ByteString -> IO ()
gzWriteFilePS [Char]
f ByteString
ps = [Char] -> [ByteString] -> IO ()
gzWriteFilePSs [Char]
f [ByteString
ps]
gzWriteFilePSs :: FilePath -> [B.ByteString] -> IO ()
gzWriteFilePSs :: [Char] -> [ByteString] -> IO ()
gzWriteFilePSs [Char]
f [ByteString]
pss =
[Char] -> ByteString -> IO ()
BL.writeFile [Char]
f forall a b. (a -> b) -> a -> b
$ ByteString -> ByteString
GZ.compress forall a b. (a -> b) -> a -> b
$ [ByteString] -> ByteString
BL.fromChunks [ByteString]
pss
gzWriteHandle :: Handle -> [B.ByteString] -> IO ()
gzWriteHandle :: Handle -> [ByteString] -> IO ()
gzWriteHandle Handle
h [ByteString]
pss =
Handle -> ByteString -> IO ()
BL.hPut Handle
h forall a b. (a -> b) -> a -> b
$ ByteString -> ByteString
GZ.compress forall a b. (a -> b) -> a -> b
$ [ByteString] -> ByteString
BL.fromChunks [ByteString]
pss
gzReadStdin :: IO B.ByteString
gzReadStdin :: IO ByteString
gzReadStdin = do
ByteString
header <- Handle -> Int -> IO ByteString
B.hGet Handle
stdin Int
2
ByteString
rest <- Handle -> IO ByteString
B.hGetContents Handle
stdin
let allStdin :: ByteString
allStdin = [ByteString] -> ByteString
B.concat [ByteString
header,ByteString
rest]
forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$
if ByteString
header forall a. Eq a => a -> a -> Bool
/= [Word8] -> ByteString
B.pack [Word8
31,Word8
139]
then ByteString
allStdin
else let decompress :: ByteString -> [ByteString]
decompress = forall a b. (a, b) -> a
fst forall b c a. (b -> c) -> (a -> b) -> a -> c
. Maybe Int -> ByteString -> ([ByteString], Bool)
gzDecompress forall a. Maybe a
Nothing
compressed :: ByteString
compressed = [ByteString] -> ByteString
BL.fromChunks [ByteString
allStdin]
in
[ByteString] -> ByteString
B.concat forall a b. (a -> b) -> a -> b
$ ByteString -> [ByteString]
decompress ByteString
compressed
type FileSegment = (FilePath, Maybe (Int64, Int))
readSegment :: FileSegment -> IO BL.ByteString
readSegment :: FileSegment -> IO ByteString
readSegment ([Char]
f,Maybe (Int64, Int)
range) = do
ByteString
bs <- IO ByteString
tryToRead
forall a. IO a -> (IOError -> IO a) -> IO a
`catchIOError` (\IOError
_ -> do
FileOffset
size <- FileStatus -> FileOffset
fileSize forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` [Char] -> IO FileStatus
getSymbolicLinkStatus [Char]
f
if FileOffset
size forall a. Eq a => a -> a -> Bool
== FileOffset
0
then forall (m :: * -> *) a. Monad m => a -> m a
return ByteString
B.empty
else IO ()
performGC forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> IO ByteString
tryToRead)
forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ [ByteString] -> ByteString
BL.fromChunks [ByteString
bs]
where
tryToRead :: IO ByteString
tryToRead =
case Maybe (Int64, Int)
range of
Maybe (Int64, Int)
Nothing -> [Char] -> IO ByteString
B.readFile [Char]
f
Just (Int64
off, Int
size) -> forall r. [Char] -> IOMode -> (Handle -> IO r) -> IO r
withFile [Char]
f IOMode
ReadMode forall a b. (a -> b) -> a -> b
$ \Handle
h -> do
Handle -> SeekMode -> Integer -> IO ()
hSeek Handle
h SeekMode
AbsoluteSeek forall a b. (a -> b) -> a -> b
$ forall a b. (Integral a, Num b) => a -> b
fromIntegral Int64
off
Handle -> Int -> IO ByteString
B.hGet Handle
h Int
size
{-# INLINE readSegment #-}
mmapFilePS :: FilePath -> IO B.ByteString
#if mingw32_HOST_OS
mmapFilePS = B.readFile
#else
mmapFilePS :: [Char] -> IO ByteString
mmapFilePS [Char]
f =
[Char] -> Maybe (Int64, Int) -> IO ByteString
mmapFileByteString [Char]
f forall a. Maybe a
Nothing
forall a. IO a -> (IOError -> IO a) -> IO a
`catchIOError` (\IOError
_ -> do
FileOffset
size <- FileStatus -> FileOffset
fileSize forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` [Char] -> IO FileStatus
getSymbolicLinkStatus [Char]
f
if FileOffset
size forall a. Eq a => a -> a -> Bool
== FileOffset
0
then forall (m :: * -> *) a. Monad m => a -> m a
return ByteString
B.empty
else IO ()
performGC forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> [Char] -> Maybe (Int64, Int) -> IO ByteString
mmapFileByteString [Char]
f forall a. Maybe a
Nothing)
#endif
fromPS2Hex :: B.ByteString -> B.ByteString
fromPS2Hex :: ByteString -> ByteString
fromPS2Hex = ByteString -> ByteString
B16.encode
fromHex2PS :: B.ByteString -> B.ByteString
fromHex2PS :: ByteString -> ByteString
fromHex2PS ByteString
s =
case ByteString -> Either [Char] ByteString
B16.decode ByteString
s of
#if MIN_VERSION_base16_bytestring(1,0,0)
Right ByteString
result -> ByteString
result
Left [Char]
msg -> forall a e. Exception e => e -> a
throw forall a b. (a -> b) -> a -> b
$ [Char] -> IOError
userError forall a b. (a -> b) -> a -> b
$ [Char]
"fromHex2PS: input is not hex encoded: "forall a. [a] -> [a] -> [a]
++[Char]
msg
#else
(result, rest) | B.null rest -> result
_ -> throw $ userError $ "fromHex2PS: input is not hex encoded"
#endif
propHexConversion :: B.ByteString -> Bool
propHexConversion :: ByteString -> Bool
propHexConversion ByteString
x = ByteString -> ByteString
fromHex2PS (ByteString -> ByteString
fromPS2Hex ByteString
x) forall a. Eq a => a -> a -> Bool
== ByteString
x
betweenLinesPS :: B.ByteString -> B.ByteString -> B.ByteString
-> Maybe B.ByteString
betweenLinesPS :: ByteString -> ByteString -> ByteString -> Maybe ByteString
betweenLinesPS ByteString
start ByteString
end ByteString
ps =
case ByteString -> ByteString -> (ByteString, ByteString)
B.breakSubstring ByteString
start_line ByteString
ps of
(ByteString
before_start, ByteString
at_start)
| Bool -> Bool
not (ByteString -> Bool
B.null ByteString
at_start)
, ByteString -> Bool
B.null ByteString
before_start Bool -> Bool -> Bool
|| ByteString -> Char
BC.last ByteString
before_start forall a. Eq a => a -> a -> Bool
== Char
'\n' ->
case ByteString -> ByteString -> (ByteString, ByteString)
B.breakSubstring ByteString
end_line (Int -> ByteString -> ByteString
B.drop (ByteString -> Int
B.length ByteString
start_line) ByteString
at_start) of
(ByteString
before_end, ByteString
at_end)
| Bool -> Bool
not (ByteString -> Bool
B.null ByteString
at_end)
, ByteString -> Bool
B.null ByteString
before_end Bool -> Bool -> Bool
|| ByteString -> Char
BC.last ByteString
before_end forall a. Eq a => a -> a -> Bool
== Char
'\n' -> forall a. a -> Maybe a
Just ByteString
before_end
| Bool
otherwise -> forall a. Maybe a
Nothing
| Bool
otherwise -> forall a. Maybe a
Nothing
where
start_line :: ByteString
start_line = ByteString -> Char -> ByteString
BC.snoc ByteString
start Char
'\n'
end_line :: ByteString
end_line = ByteString -> Char -> ByteString
BC.snoc ByteString
end Char
'\n'
spec_betweenLinesPS :: B.ByteString -> B.ByteString -> B.ByteString
-> Maybe B.ByteString
spec_betweenLinesPS :: ByteString -> ByteString -> ByteString -> Maybe ByteString
spec_betweenLinesPS ByteString
start ByteString
end ByteString
ps =
case forall a. (a -> Bool) -> [a] -> ([a], [a])
break (ByteString
start forall a. Eq a => a -> a -> Bool
==) (ByteString -> [ByteString]
linesPS ByteString
ps) of
([ByteString]
_, ByteString
_:[ByteString]
after_start) ->
case forall a. (a -> Bool) -> [a] -> ([a], [a])
break (ByteString
end forall a. Eq a => a -> a -> Bool
==) [ByteString]
after_start of
([ByteString]
before_end, ByteString
_:[ByteString]
_) ->
forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ [ByteString] -> ByteString
BC.unlines [ByteString]
before_end
([ByteString], [ByteString])
_ -> forall a. Maybe a
Nothing
([ByteString], [ByteString])
_ -> forall a. Maybe a
Nothing
isAscii :: B.ByteString -> Bool
isAscii :: ByteString -> Bool
isAscii = (Word8 -> Bool) -> ByteString -> Bool
B.all (forall a. Ord a => a -> a -> Bool
< Word8
128)
unpackPSFromUTF8 :: B.ByteString -> String
unpackPSFromUTF8 :: ByteString -> [Char]
unpackPSFromUTF8 = forall a. IO a -> a
unsafePerformIO forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> IO [Char]
decodeUtf8
packStringToUTF8 :: String -> B.ByteString
packStringToUTF8 :: [Char] -> ByteString
packStringToUTF8 = forall a. IO a -> a
unsafePerformIO forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> IO ByteString
encodeUtf8
decodeLocale :: B.ByteString -> String
decodeLocale :: ByteString -> [Char]
decodeLocale = forall a. IO a -> a
unsafePerformIO forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> IO [Char]
decode
encodeLocale :: String -> B.ByteString
encodeLocale :: [Char] -> ByteString
encodeLocale [Char]
s = forall a. IO a -> a
unsafePerformIO forall a b. (a -> b) -> a -> b
$ [Char] -> IO ByteString
encode [Char]
s forall a. IO a -> (IOError -> IO a) -> IO a
`catchIOError` (\IOError
_ -> [Char] -> IO ByteString
encodeUtf8 [Char]
s)