{-# LANGUAGE CPP #-}
module Codec.Text.IConv (
convert,
EncodingName,
convertFuzzy,
Fuzzy(..),
convertStrictly,
convertLazily,
ConversionError(..),
reportConversionError,
Span(..),
) where
import Prelude hiding (length, span)
import Control.Exception (assert)
import qualified Control.Exception as Exception
import Foreign.C.Error as C.Error (Errno, errnoToIOError)
import qualified Data.ByteString.Lazy as L (ByteString, toChunks, fromChunks)
import qualified Data.ByteString.Lazy.Internal as L (defaultChunkSize)
import qualified Data.ByteString as S
import qualified Codec.Text.IConv.Internal as IConv
import Codec.Text.IConv.Internal (IConv)
type EncodingName = String
data Span =
Span !S.ByteString
| ConversionError !ConversionError
data ConversionError =
UnsuportedConversion EncodingName EncodingName
| InvalidChar Int
| IncompleteChar Int
| UnexpectedError C.Error.Errno
reportConversionError :: ConversionError -> IOError
reportConversionError :: ConversionError -> IOError
reportConversionError conversionError :: ConversionError
conversionError = case ConversionError
conversionError of
UnsuportedConversion fromEncoding :: EncodingName
fromEncoding toEncoding :: EncodingName
toEncoding
-> EncodingName -> IOError
err (EncodingName -> IOError) -> EncodingName -> IOError
forall a b. (a -> b) -> a -> b
$ "cannot convert from string encoding "
EncodingName -> EncodingName -> EncodingName
forall a. [a] -> [a] -> [a]
++ EncodingName -> EncodingName
forall a. Show a => a -> EncodingName
show EncodingName
fromEncoding EncodingName -> EncodingName -> EncodingName
forall a. [a] -> [a] -> [a]
++ " to string encoding "
EncodingName -> EncodingName -> EncodingName
forall a. [a] -> [a] -> [a]
++ EncodingName -> EncodingName
forall a. Show a => a -> EncodingName
show EncodingName
toEncoding
InvalidChar inputPos :: Int
inputPos -> EncodingName -> IOError
err (EncodingName -> IOError) -> EncodingName -> IOError
forall a b. (a -> b) -> a -> b
$ "invalid input sequence at byte offset "
EncodingName -> EncodingName -> EncodingName
forall a. [a] -> [a] -> [a]
++ Int -> EncodingName
forall a. Show a => a -> EncodingName
show Int
inputPos
IncompleteChar inputPos :: Int
inputPos -> EncodingName -> IOError
err (EncodingName -> IOError) -> EncodingName -> IOError
forall a b. (a -> b) -> a -> b
$ "incomplete input sequence at byte offset "
EncodingName -> EncodingName -> EncodingName
forall a. [a] -> [a] -> [a]
++ Int -> EncodingName
forall a. Show a => a -> EncodingName
show Int
inputPos
UnexpectedError errno :: Errno
errno -> EncodingName
-> Errno -> Maybe Handle -> Maybe EncodingName -> IOError
C.Error.errnoToIOError
"Codec.Text.IConv: unexpected error" Errno
errno
Maybe Handle
forall a. Maybe a
Nothing Maybe EncodingName
forall a. Maybe a
Nothing
where err :: EncodingName -> IOError
err msg :: EncodingName
msg = EncodingName -> IOError
userError (EncodingName -> IOError) -> EncodingName -> IOError
forall a b. (a -> b) -> a -> b
$ "Codec.Text.IConv: " EncodingName -> EncodingName -> EncodingName
forall a. [a] -> [a] -> [a]
++ EncodingName
msg
{-# NOINLINE convert #-}
convert :: EncodingName
-> EncodingName
-> L.ByteString
-> L.ByteString
convert :: EncodingName -> EncodingName -> ByteString -> ByteString
convert fromEncoding :: EncodingName
fromEncoding toEncoding :: EncodingName
toEncoding =
[ByteString] -> ByteString
L.fromChunks
([ByteString] -> ByteString)
-> (ByteString -> [ByteString]) -> ByteString -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Span -> [ByteString] -> [ByteString])
-> [ByteString] -> [Span] -> [ByteString]
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr Span -> [ByteString] -> [ByteString]
span []
([Span] -> [ByteString])
-> (ByteString -> [Span]) -> ByteString -> [ByteString]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. EncodingName -> EncodingName -> ByteString -> [Span]
convertLazily EncodingName
fromEncoding EncodingName
toEncoding
where
span :: Span -> [ByteString] -> [ByteString]
span (Span c :: ByteString
c) cs :: [ByteString]
cs = ByteString
c ByteString -> [ByteString] -> [ByteString]
forall a. a -> [a] -> [a]
: [ByteString]
cs
span (ConversionError e :: ConversionError
e) _ =
#if MIN_VERSION_base(4,0,0)
IOError -> [ByteString]
forall a e. Exception e => e -> a
Exception.throw (ConversionError -> IOError
reportConversionError ConversionError
e)
#else
Exception.throw (Exception.IOException (reportConversionError e))
#endif
data Fuzzy = Transliterate | Discard
convertFuzzy :: Fuzzy
-> EncodingName
-> EncodingName
-> L.ByteString
-> L.ByteString
convertFuzzy :: Fuzzy -> EncodingName -> EncodingName -> ByteString -> ByteString
convertFuzzy fuzzy :: Fuzzy
fuzzy fromEncoding :: EncodingName
fromEncoding toEncoding :: EncodingName
toEncoding =
[ByteString] -> ByteString
L.fromChunks
([ByteString] -> ByteString)
-> (ByteString -> [ByteString]) -> ByteString -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Span -> [ByteString] -> [ByteString])
-> [ByteString] -> [Span] -> [ByteString]
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr Span -> [ByteString] -> [ByteString]
span []
([Span] -> [ByteString])
-> (ByteString -> [Span]) -> ByteString -> [ByteString]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. InvalidCharBehaviour
-> EncodingName -> EncodingName -> ByteString -> [Span]
convertInternal InvalidCharBehaviour
IgnoreInvalidChar EncodingName
fromEncoding (EncodingName
toEncoding EncodingName -> EncodingName -> EncodingName
forall a. [a] -> [a] -> [a]
++ EncodingName
mode)
where
mode :: EncodingName
mode = case Fuzzy
fuzzy of
Transliterate -> "//IGNORE,TRANSLIT"
Discard -> "//IGNORE"
span :: Span -> [ByteString] -> [ByteString]
span (Span c :: ByteString
c) cs :: [ByteString]
cs = ByteString
c ByteString -> [ByteString] -> [ByteString]
forall a. a -> [a] -> [a]
: [ByteString]
cs
span (ConversionError _) cs :: [ByteString]
cs = [ByteString]
cs
{-# NOINLINE convertStrictly #-}
convertStrictly :: EncodingName
-> EncodingName
-> L.ByteString
-> Either L.ByteString
ConversionError
convertStrictly :: EncodingName
-> EncodingName -> ByteString -> Either ByteString ConversionError
convertStrictly fromEncoding :: EncodingName
fromEncoding toEncoding :: EncodingName
toEncoding =
[ByteString] -> [Span] -> Either ByteString ConversionError
strictify []
([Span] -> Either ByteString ConversionError)
-> (ByteString -> [Span])
-> ByteString
-> Either ByteString ConversionError
forall b c a. (b -> c) -> (a -> b) -> a -> c
. EncodingName -> EncodingName -> ByteString -> [Span]
convertLazily EncodingName
fromEncoding EncodingName
toEncoding
where
strictify :: [S.ByteString] -> [Span] -> Either L.ByteString ConversionError
strictify :: [ByteString] -> [Span] -> Either ByteString ConversionError
strictify cs :: [ByteString]
cs [] = ByteString -> Either ByteString ConversionError
forall a b. a -> Either a b
Left ([ByteString] -> ByteString
L.fromChunks ([ByteString] -> [ByteString]
forall a. [a] -> [a]
reverse [ByteString]
cs))
strictify cs :: [ByteString]
cs (Span c :: ByteString
c : ss :: [Span]
ss) = [ByteString] -> [Span] -> Either ByteString ConversionError
strictify (ByteString
cByteString -> [ByteString] -> [ByteString]
forall a. a -> [a] -> [a]
:[ByteString]
cs) [Span]
ss
strictify _ (ConversionError e :: ConversionError
e:_) = ConversionError -> Either ByteString ConversionError
forall a b. b -> Either a b
Right ConversionError
e
{-# NOINLINE convertLazily #-}
convertLazily :: EncodingName
-> EncodingName
-> L.ByteString
-> [Span]
convertLazily :: EncodingName -> EncodingName -> ByteString -> [Span]
convertLazily = InvalidCharBehaviour
-> EncodingName -> EncodingName -> ByteString -> [Span]
convertInternal InvalidCharBehaviour
StopOnInvalidChar
data InvalidCharBehaviour = StopOnInvalidChar | IgnoreInvalidChar
convertInternal :: InvalidCharBehaviour
-> EncodingName -> EncodingName
-> L.ByteString -> [Span]
convertInternal :: InvalidCharBehaviour
-> EncodingName -> EncodingName -> ByteString -> [Span]
convertInternal ignore :: InvalidCharBehaviour
ignore fromEncoding :: EncodingName
fromEncoding toEncoding :: EncodingName
toEncoding input :: ByteString
input =
EncodingName
-> EncodingName -> (InitStatus -> IConv [Span]) -> [Span]
forall a.
EncodingName -> EncodingName -> (InitStatus -> IConv a) -> a
IConv.run EncodingName
fromEncoding EncodingName
toEncoding ((InitStatus -> IConv [Span]) -> [Span])
-> (InitStatus -> IConv [Span]) -> [Span]
forall a b. (a -> b) -> a -> b
$ \status :: InitStatus
status -> case InitStatus
status of
IConv.InitOk -> do Int -> IConv ()
IConv.newOutputBuffer Int
outChunkSize
InvalidCharBehaviour -> [ByteString] -> IConv [Span]
fillInputBuffer InvalidCharBehaviour
ignore (ByteString -> [ByteString]
L.toChunks ByteString
input)
IConv.UnsupportedConversion -> ConversionError -> IConv [Span]
failConversion (EncodingName -> EncodingName -> ConversionError
UnsuportedConversion
EncodingName
fromEncoding
EncodingName
toEncoding)
IConv.UnexpectedInitError errno :: Errno
errno -> ConversionError -> IConv [Span]
failConversion (Errno -> ConversionError
UnexpectedError Errno
errno)
fillInputBuffer :: InvalidCharBehaviour -> [S.ByteString] -> IConv [Span]
fillInputBuffer :: InvalidCharBehaviour -> [ByteString] -> IConv [Span]
fillInputBuffer ignore :: InvalidCharBehaviour
ignore (inChunk :: ByteString
inChunk : inChunks :: [ByteString]
inChunks) = do
ByteString -> IConv ()
IConv.pushInputBuffer ByteString
inChunk
InvalidCharBehaviour -> [ByteString] -> IConv [Span]
drainBuffers InvalidCharBehaviour
ignore [ByteString]
inChunks
fillInputBuffer _ignore :: InvalidCharBehaviour
_ignore [] = do
Int
outputBufferBytesAvailable <- IConv Int
IConv.outputBufferBytesAvailable
IConv ()
IConv.finalise
if Int
outputBufferBytesAvailable Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> 0
then do ByteString
outChunk <- IConv ByteString
IConv.popOutputBuffer
[Span] -> IConv [Span]
forall (m :: * -> *) a. Monad m => a -> m a
return [ByteString -> Span
Span ByteString
outChunk]
else [Span] -> IConv [Span]
forall (m :: * -> *) a. Monad m => a -> m a
return []
drainBuffers :: InvalidCharBehaviour -> [S.ByteString] -> IConv [Span]
drainBuffers :: InvalidCharBehaviour -> [ByteString] -> IConv [Span]
drainBuffers ignore :: InvalidCharBehaviour
ignore inChunks :: [ByteString]
inChunks = do
Bool
inputBufferEmpty_ <- IConv Bool
IConv.inputBufferEmpty
Bool
outputBufferFull <- IConv Bool
IConv.outputBufferFull
Bool -> IConv () -> IConv ()
forall a. (?callStack::CallStack) => Bool -> a -> a
assert (Bool -> Bool
not Bool
outputBufferFull Bool -> Bool -> Bool
&& Bool -> Bool
not Bool
inputBufferEmpty_) (IConv () -> IConv ()) -> IConv () -> IConv ()
forall a b. (a -> b) -> a -> b
$ () -> IConv ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
Status
status <- IConv Status
IConv.iconv
case Status
status of
IConv.InputEmpty -> do
Bool
inputBufferEmpty <- IConv Bool
IConv.inputBufferEmpty
Bool -> IConv [Span] -> IConv [Span]
forall a. (?callStack::CallStack) => Bool -> a -> a
assert Bool
inputBufferEmpty (IConv [Span] -> IConv [Span]) -> IConv [Span] -> IConv [Span]
forall a b. (a -> b) -> a -> b
$ InvalidCharBehaviour -> [ByteString] -> IConv [Span]
fillInputBuffer InvalidCharBehaviour
ignore [ByteString]
inChunks
IConv.OutputFull -> do
ByteString
outChunk <- IConv ByteString
IConv.popOutputBuffer
[Span]
outChunks <- IConv [Span] -> IConv [Span]
forall a. IConv a -> IConv a
IConv.unsafeInterleave (IConv [Span] -> IConv [Span]) -> IConv [Span] -> IConv [Span]
forall a b. (a -> b) -> a -> b
$ do
Int -> IConv ()
IConv.newOutputBuffer Int
outChunkSize
InvalidCharBehaviour -> [ByteString] -> IConv [Span]
drainBuffers InvalidCharBehaviour
ignore [ByteString]
inChunks
[Span] -> IConv [Span]
forall (m :: * -> *) a. Monad m => a -> m a
return (ByteString -> Span
Span ByteString
outChunk Span -> [Span] -> [Span]
forall a. a -> [a] -> [a]
: [Span]
outChunks)
IConv.InvalidChar -> InvalidCharBehaviour -> [ByteString] -> IConv [Span]
invalidChar InvalidCharBehaviour
ignore [ByteString]
inChunks
IConv.IncompleteChar -> InvalidCharBehaviour -> [ByteString] -> IConv [Span]
fixupBoundary InvalidCharBehaviour
ignore [ByteString]
inChunks
IConv.UnexpectedError errno :: Errno
errno -> ConversionError -> IConv [Span]
failConversion (Errno -> ConversionError
UnexpectedError Errno
errno)
fixupBoundary :: InvalidCharBehaviour -> [S.ByteString] -> IConv [Span]
fixupBoundary :: InvalidCharBehaviour -> [ByteString] -> IConv [Span]
fixupBoundary _ignore :: InvalidCharBehaviour
_ignore [] = do
Int
inputPos <- IConv Int
IConv.inputPosition
ConversionError -> IConv [Span]
failConversion (Int -> ConversionError
IncompleteChar Int
inputPos)
fixupBoundary ignore :: InvalidCharBehaviour
ignore inChunks :: [ByteString]
inChunks@(inChunk :: ByteString
inChunk : inChunks' :: [ByteString]
inChunks') = do
Int
inSize <- IConv Int
IConv.inputBufferSize
Bool -> IConv () -> IConv ()
forall a. (?callStack::CallStack) => Bool -> a -> a
assert (Int
inSize Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
tmpChunkSize) (IConv () -> IConv ()) -> IConv () -> IConv ()
forall a b. (a -> b) -> a -> b
$ () -> IConv ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
let extraBytes :: Int
extraBytes = Int
tmpChunkSize Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
inSize
if ByteString -> Int
S.length ByteString
inChunk Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
extraBytes
then do
(ByteString -> ByteString) -> IConv ()
IConv.replaceInputBuffer (ByteString -> ByteString -> ByteString
`S.append` ByteString
inChunk)
InvalidCharBehaviour -> [ByteString] -> IConv [Span]
drainBuffers InvalidCharBehaviour
ignore [ByteString]
inChunks'
else do
(ByteString -> ByteString) -> IConv ()
IConv.replaceInputBuffer (ByteString -> ByteString -> ByteString
`S.append` Int -> ByteString -> ByteString
S.take Int
extraBytes ByteString
inChunk)
Int
before <- IConv Int
IConv.inputBufferSize
Bool -> IConv () -> IConv ()
forall a. (?callStack::CallStack) => Bool -> a -> a
assert (Int
before Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
tmpChunkSize) (IConv () -> IConv ()) -> IConv () -> IConv ()
forall a b. (a -> b) -> a -> b
$ () -> IConv ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
Status
status <- IConv Status
IConv.iconv
Int
after <- IConv Int
IConv.inputBufferSize
let consumed :: Int
consumed = Int
before Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
after
case Status
status of
IConv.InputEmpty ->
Bool -> IConv [Span] -> IConv [Span]
forall a. (?callStack::CallStack) => Bool -> a -> a
assert (Int
consumed Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
tmpChunkSize) (IConv [Span] -> IConv [Span]) -> IConv [Span] -> IConv [Span]
forall a b. (a -> b) -> a -> b
$
InvalidCharBehaviour -> [ByteString] -> IConv [Span]
fillInputBuffer InvalidCharBehaviour
ignore (Int -> ByteString -> ByteString
S.drop Int
extraBytes ByteString
inChunk ByteString -> [ByteString] -> [ByteString]
forall a. a -> [a] -> [a]
: [ByteString]
inChunks')
IConv.OutputFull -> do
ByteString
outChunk <- IConv ByteString
IConv.popOutputBuffer
[Span]
outChunks <- IConv [Span] -> IConv [Span]
forall a. IConv a -> IConv a
IConv.unsafeInterleave (IConv [Span] -> IConv [Span]) -> IConv [Span] -> IConv [Span]
forall a b. (a -> b) -> a -> b
$ do
Int -> IConv ()
IConv.newOutputBuffer Int
outChunkSize
InvalidCharBehaviour -> [ByteString] -> IConv [Span]
drainBuffers InvalidCharBehaviour
ignore [ByteString]
inChunks
[Span] -> IConv [Span]
forall (m :: * -> *) a. Monad m => a -> m a
return (ByteString -> Span
Span ByteString
outChunk Span -> [Span] -> [Span]
forall a. a -> [a] -> [a]
: [Span]
outChunks)
IConv.InvalidChar -> InvalidCharBehaviour -> [ByteString] -> IConv [Span]
invalidChar InvalidCharBehaviour
ignore [ByteString]
inChunks
IConv.IncompleteChar ->
Bool -> IConv [Span] -> IConv [Span]
forall a. (?callStack::CallStack) => Bool -> a -> a
assert (Int
inSize Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
consumed Bool -> Bool -> Bool
&& Int
consumed Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
tmpChunkSize) (IConv [Span] -> IConv [Span]) -> IConv [Span] -> IConv [Span]
forall a b. (a -> b) -> a -> b
$
InvalidCharBehaviour -> [ByteString] -> IConv [Span]
drainBuffers InvalidCharBehaviour
ignore (Int -> ByteString -> ByteString
S.drop (Int
consumed Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
inSize) ByteString
inChunk ByteString -> [ByteString] -> [ByteString]
forall a. a -> [a] -> [a]
: [ByteString]
inChunks')
IConv.UnexpectedError errno :: Errno
errno -> ConversionError -> IConv [Span]
failConversion (Errno -> ConversionError
UnexpectedError Errno
errno)
invalidChar :: InvalidCharBehaviour -> [S.ByteString] -> IConv [Span]
invalidChar :: InvalidCharBehaviour -> [ByteString] -> IConv [Span]
invalidChar StopOnInvalidChar _ = do
Int
inputPos <- IConv Int
IConv.inputPosition
ConversionError -> IConv [Span]
failConversion (Int -> ConversionError
InvalidChar Int
inputPos)
invalidChar IgnoreInvalidChar inChunks :: [ByteString]
inChunks = do
Int
inputPos <- IConv Int
IConv.inputPosition
let invalidCharError :: Span
invalidCharError = ConversionError -> Span
ConversionError (Int -> ConversionError
InvalidChar Int
inputPos)
Int
outputBufferBytesAvailable <- IConv Int
IConv.outputBufferBytesAvailable
if Int
outputBufferBytesAvailable Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> 0
then do ByteString
outChunk <- IConv ByteString
IConv.popOutputBuffer
[Span]
outChunks <- IConv [Span] -> IConv [Span]
forall a. IConv a -> IConv a
IConv.unsafeInterleave (IConv [Span] -> IConv [Span]) -> IConv [Span] -> IConv [Span]
forall a b. (a -> b) -> a -> b
$ do
Int -> IConv ()
IConv.newOutputBuffer Int
outChunkSize
Bool
inputBufferEmpty <- IConv Bool
IConv.inputBufferEmpty
if Bool
inputBufferEmpty
then InvalidCharBehaviour -> [ByteString] -> IConv [Span]
fillInputBuffer InvalidCharBehaviour
IgnoreInvalidChar [ByteString]
inChunks
else InvalidCharBehaviour -> [ByteString] -> IConv [Span]
drainBuffers InvalidCharBehaviour
IgnoreInvalidChar [ByteString]
inChunks
[Span] -> IConv [Span]
forall (m :: * -> *) a. Monad m => a -> m a
return (ByteString -> Span
Span ByteString
outChunk Span -> [Span] -> [Span]
forall a. a -> [a] -> [a]
: Span
invalidCharError Span -> [Span] -> [Span]
forall a. a -> [a] -> [a]
: [Span]
outChunks)
else do [Span]
outChunks <- IConv [Span] -> IConv [Span]
forall a. IConv a -> IConv a
IConv.unsafeInterleave (IConv [Span] -> IConv [Span]) -> IConv [Span] -> IConv [Span]
forall a b. (a -> b) -> a -> b
$ do
Int -> IConv ()
IConv.newOutputBuffer Int
outChunkSize
Bool
inputBufferEmpty <- IConv Bool
IConv.inputBufferEmpty
if Bool
inputBufferEmpty
then InvalidCharBehaviour -> [ByteString] -> IConv [Span]
fillInputBuffer InvalidCharBehaviour
IgnoreInvalidChar [ByteString]
inChunks
else InvalidCharBehaviour -> [ByteString] -> IConv [Span]
drainBuffers InvalidCharBehaviour
IgnoreInvalidChar [ByteString]
inChunks
[Span] -> IConv [Span]
forall (m :: * -> *) a. Monad m => a -> m a
return (Span
invalidCharError Span -> [Span] -> [Span]
forall a. a -> [a] -> [a]
: [Span]
outChunks)
failConversion :: ConversionError -> IConv [Span]
failConversion :: ConversionError -> IConv [Span]
failConversion err :: ConversionError
err = do
Int
outputBufferBytesAvailable <- IConv Int
IConv.outputBufferBytesAvailable
IConv ()
IConv.finalise
if Int
outputBufferBytesAvailable Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> 0
then do ByteString
outChunk <- IConv ByteString
IConv.popOutputBuffer
[Span] -> IConv [Span]
forall (m :: * -> *) a. Monad m => a -> m a
return [ByteString -> Span
Span ByteString
outChunk, ConversionError -> Span
ConversionError ConversionError
err]
else [Span] -> IConv [Span]
forall (m :: * -> *) a. Monad m => a -> m a
return [ ConversionError -> Span
ConversionError ConversionError
err]
outChunkSize :: Int
outChunkSize :: Int
outChunkSize = Int
L.defaultChunkSize
tmpChunkSize :: Int
tmpChunkSize :: Int
tmpChunkSize = 16