{-# LANGUAGE Trustworthy #-}
{-# LANGUAGE CPP, NoImplicitPrelude, NondecreasingIndentation,
RecordWildCards, ScopedTypeVariables,
UnboxedTuples #-}
{-# OPTIONS_GHC -Wno-name-shadowing #-}
module GHC.Internal.IO.Encoding.CodePage.API (
mkCodePageEncoding
) where
#include <ghcautoconf.h>
import GHC.Internal.Ptr
import GHC.Internal.Foreign.C.Types
import GHC.Internal.Foreign.Marshal.Alloc
import GHC.Internal.Foreign.Marshal.Array
import GHC.Internal.Foreign.Storable
import GHC.Internal.Data.Bits
import GHC.Internal.Data.Either
import GHC.Internal.Word
import GHC.Internal.Base
import GHC.Internal.List
import GHC.Internal.IO.Buffer
import GHC.Internal.IO.Encoding.Failure
import GHC.Internal.IO.Encoding.Types
import GHC.Internal.IO.Encoding.UTF16
import GHC.Internal.Num
import GHC.Internal.Show
import GHC.Internal.Real
import GHC.Internal.Windows hiding (LPCSTR)
import GHC.Internal.ForeignPtr (castForeignPtr)
import GHC.Internal.System.Posix.Internals
#if defined(javascript_HOST_ARCH)
mkCodePageEncoding :: String
mkCodePageEncoding = ""
#else
c_DEBUG_DUMP :: Bool
c_DEBUG_DUMP :: Bool
c_DEBUG_DUMP = Bool
False
debugIO :: String -> IO ()
debugIO :: String -> IO ()
debugIO String
s
| Bool
c_DEBUG_DUMP = String -> IO ()
puts String
s
| Bool
otherwise = () -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
type LPCSTR = Ptr Word8
mAX_DEFAULTCHAR :: Int
mAX_DEFAULTCHAR :: Int
mAX_DEFAULTCHAR = Int
2
mAX_LEADBYTES :: Int
mAX_LEADBYTES :: Int
mAX_LEADBYTES = Int
12
data CPINFO = CPINFO {
CPINFO -> Word32
maxCharSize :: UINT,
CPINFO -> [Word8]
defaultChar :: [BYTE],
CPINFO -> [Word8]
leadByte :: [BYTE]
}
instance Storable CPINFO where
sizeOf :: CPINFO -> Int
sizeOf CPINFO
_ = Word32 -> Int
forall a. Storable a => a -> Int
sizeOf (Word32
forall a. HasCallStack => a
undefined :: UINT) Int -> Int -> Int
forall a. Num a => a -> a -> a
+ (Int
mAX_DEFAULTCHAR Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
mAX_LEADBYTES) Int -> Int -> Int
forall a. Num a => a -> a -> a
* Word8 -> Int
forall a. Storable a => a -> Int
sizeOf (Word8
forall a. HasCallStack => a
undefined :: BYTE)
alignment :: CPINFO -> Int
alignment CPINFO
_ = CInt -> Int
forall a. Storable a => a -> Int
alignment (CInt
forall a. HasCallStack => a
undefined :: CInt)
peek :: Ptr CPINFO -> IO CPINFO
peek Ptr CPINFO
ptr = do
ptr <- Ptr Word32 -> IO (Ptr Word32)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Ptr Word32 -> IO (Ptr Word32)) -> Ptr Word32 -> IO (Ptr Word32)
forall a b. (a -> b) -> a -> b
$ Ptr CPINFO -> Ptr Word32
forall a b. Ptr a -> Ptr b
castPtr Ptr CPINFO
ptr
a <- peek ptr
ptr <- return $ castPtr $ advancePtr ptr 1
b <- peekArray mAX_DEFAULTCHAR ptr
c <- peekArray mAX_LEADBYTES (advancePtr ptr mAX_DEFAULTCHAR)
return $ CPINFO a b c
poke :: Ptr CPINFO -> CPINFO -> IO ()
poke Ptr CPINFO
ptr CPINFO
val = do
ptr <- Ptr Word32 -> IO (Ptr Word32)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Ptr Word32 -> IO (Ptr Word32)) -> Ptr Word32 -> IO (Ptr Word32)
forall a b. (a -> b) -> a -> b
$ Ptr CPINFO -> Ptr Word32
forall a b. Ptr a -> Ptr b
castPtr Ptr CPINFO
ptr
poke ptr (maxCharSize val)
ptr <- return $ castPtr $ advancePtr ptr 1
pokeArray' "CPINFO.defaultChar" mAX_DEFAULTCHAR ptr (defaultChar val)
pokeArray' "CPINFO.leadByte" mAX_LEADBYTES (advancePtr ptr mAX_DEFAULTCHAR) (leadByte val)
pokeArray' :: Storable a => String -> Int -> Ptr a -> [a] -> IO ()
pokeArray' :: forall a. Storable a => String -> Int -> Ptr a -> [a] -> IO ()
pokeArray' String
msg Int
sz Ptr a
ptr [a]
xs | [a] -> Int
forall a. [a] -> Int
length [a]
xs Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
sz = Ptr a -> [a] -> IO ()
forall a. Storable a => Ptr a -> [a] -> IO ()
pokeArray Ptr a
ptr [a]
xs
| Bool
otherwise = String -> IO ()
forall a. String -> a
errorWithoutStackTrace (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
msg String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
": expected " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
sz String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" elements in list but got " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show ([a] -> Int
forall a. [a] -> Int
length [a]
xs)
foreign import ccall unsafe "windows.h GetCPInfo"
c_GetCPInfo :: UINT
-> Ptr CPINFO
-> IO BOOL
foreign import ccall unsafe "windows.h MultiByteToWideChar"
c_MultiByteToWideChar :: UINT
-> DWORD
-> LPCSTR
-> CInt
-> LPWSTR
-> CInt
-> IO CInt
foreign import ccall unsafe "windows.h WideCharToMultiByte"
c_WideCharToMultiByte :: UINT
-> DWORD
-> LPWSTR
-> CInt
-> LPCSTR
-> CInt
-> LPCSTR
-> LPBOOL
-> IO CInt
foreign import ccall unsafe "windows.h IsDBCSLeadByteEx"
c_IsDBCSLeadByteEx :: UINT
-> BYTE
-> IO BOOL
mkCodePageEncoding :: CodingFailureMode -> Word32 -> TextEncoding
mkCodePageEncoding :: CodingFailureMode -> Word32 -> TextEncoding
mkCodePageEncoding CodingFailureMode
cfm Word32
cp
= TextEncoding {
textEncodingName :: String
textEncodingName = String
"CP" String -> String -> String
forall a. [a] -> [a] -> [a]
++ Word32 -> String
forall a. Show a => a -> String
show Word32
cp,
mkTextDecoder :: IO (TextDecoder ())
mkTextDecoder = (Buffer Word8
-> Buffer CharBufElem -> IO (Buffer Word8, Buffer CharBufElem))
-> (Word32 -> Int -> CodeBuffer Word8 CharBufElem)
-> Word32
-> IO (TextDecoder ())
forall from to.
(Buffer from -> Buffer to -> IO (Buffer from, Buffer to))
-> (Word32 -> Int -> CodeBuffer from to)
-> Word32
-> IO (BufferCodec from to ())
newCP (CodingFailureMode
-> Buffer Word8
-> Buffer CharBufElem
-> IO (Buffer Word8, Buffer CharBufElem)
recoverDecode CodingFailureMode
cfm) Word32 -> Int -> CodeBuffer Word8 CharBufElem
cpDecode Word32
cp,
mkTextEncoder :: IO (TextEncoder ())
mkTextEncoder = (Buffer CharBufElem
-> Buffer Word8 -> IO (Buffer CharBufElem, Buffer Word8))
-> (Word32 -> Int -> CodeBuffer CharBufElem Word8)
-> Word32
-> IO (TextEncoder ())
forall from to.
(Buffer from -> Buffer to -> IO (Buffer from, Buffer to))
-> (Word32 -> Int -> CodeBuffer from to)
-> Word32
-> IO (BufferCodec from to ())
newCP (CodingFailureMode
-> Buffer CharBufElem
-> Buffer Word8
-> IO (Buffer CharBufElem, Buffer Word8)
recoverEncode CodingFailureMode
cfm) Word32 -> Int -> CodeBuffer CharBufElem Word8
cpEncode Word32
cp
}
newCP :: (Buffer from -> Buffer to -> IO (Buffer from, Buffer to))
-> (Word32 -> Int -> CodeBuffer from to)
-> Word32
-> IO (BufferCodec from to ())
newCP :: forall from to.
(Buffer from -> Buffer to -> IO (Buffer from, Buffer to))
-> (Word32 -> Int -> CodeBuffer from to)
-> Word32
-> IO (BufferCodec from to ())
newCP Buffer from -> Buffer to -> IO (Buffer from, Buffer to)
rec Word32 -> Int -> CodeBuffer from to
fn Word32
cp = do
max_char_size <- (Ptr CPINFO -> IO Int) -> IO Int
forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca ((Ptr CPINFO -> IO Int) -> IO Int)
-> (Ptr CPINFO -> IO Int) -> IO Int
forall a b. (a -> b) -> a -> b
$ \Ptr CPINFO
cpinfo_ptr -> do
success <- Word32 -> Ptr CPINFO -> IO Bool
c_GetCPInfo Word32
cp Ptr CPINFO
cpinfo_ptr
when (not success) $ throwGetLastError ("GetCPInfo " ++ show cp)
fmap (fromIntegral . maxCharSize) $ peek cpinfo_ptr
debugIO $ "GetCPInfo " ++ show cp ++ " = " ++ show max_char_size
return $ BufferCodec {
encode = fn cp max_char_size,
recover = rec,
close = return (),
getState = return (),
setState = const $ return ()
}
utf16_native_encode' :: EncodeBuffer
utf16_native_decode' :: DecodeBuffer
#if defined(WORDS_BIGENDIAN)
utf16_native_encode' i o = IO $ \st -> case utf16be_encode i o st of
(# st', c, i', o' #) -> (# st', (c, i', o') #)
utf16_native_decode' i o = IO $ \st -> case utf16be_decode i o st of
(# st', c, i', o' #) -> (# st', (c, i', o') #)
#else
utf16_native_encode' :: CodeBuffer CharBufElem Word8
utf16_native_encode' Buffer CharBufElem
i Buffer Word8
o = (State# RealWorld
-> (# State# RealWorld,
(CodingProgress, Buffer CharBufElem, Buffer Word8) #))
-> IO (CodingProgress, Buffer CharBufElem, Buffer Word8)
forall a. (State# RealWorld -> (# State# RealWorld, a #)) -> IO a
IO ((State# RealWorld
-> (# State# RealWorld,
(CodingProgress, Buffer CharBufElem, Buffer Word8) #))
-> IO (CodingProgress, Buffer CharBufElem, Buffer Word8))
-> (State# RealWorld
-> (# State# RealWorld,
(CodingProgress, Buffer CharBufElem, Buffer Word8) #))
-> IO (CodingProgress, Buffer CharBufElem, Buffer Word8)
forall a b. (a -> b) -> a -> b
$ \State# RealWorld
st -> case EncodeBuffer#
utf16le_encode Buffer CharBufElem
i Buffer Word8
o State# RealWorld
st of
(# State# RealWorld
st', CodingProgress
c, Buffer CharBufElem
i', Buffer Word8
o' #) -> (# State# RealWorld
st', (CodingProgress
c, Buffer CharBufElem
i', Buffer Word8
o') #)
utf16_native_decode' :: CodeBuffer Word8 CharBufElem
utf16_native_decode' Buffer Word8
i Buffer CharBufElem
o = (State# RealWorld
-> (# State# RealWorld,
(CodingProgress, Buffer Word8, Buffer CharBufElem) #))
-> IO (CodingProgress, Buffer Word8, Buffer CharBufElem)
forall a. (State# RealWorld -> (# State# RealWorld, a #)) -> IO a
IO ((State# RealWorld
-> (# State# RealWorld,
(CodingProgress, Buffer Word8, Buffer CharBufElem) #))
-> IO (CodingProgress, Buffer Word8, Buffer CharBufElem))
-> (State# RealWorld
-> (# State# RealWorld,
(CodingProgress, Buffer Word8, Buffer CharBufElem) #))
-> IO (CodingProgress, Buffer Word8, Buffer CharBufElem)
forall a b. (a -> b) -> a -> b
$ \State# RealWorld
st -> case DecodeBuffer#
utf16le_decode Buffer Word8
i Buffer CharBufElem
o State# RealWorld
st of
(# State# RealWorld
st', CodingProgress
c, Buffer Word8
i', Buffer CharBufElem
o' #) -> (# State# RealWorld
st', (CodingProgress
c, Buffer Word8
i', Buffer CharBufElem
o') #)
#endif
saner :: CodeBuffer from to
-> Buffer from -> Buffer to
-> IO (CodingProgress, Int, Buffer from, Buffer to)
saner :: forall from to.
CodeBuffer from to
-> Buffer from
-> Buffer to
-> IO (CodingProgress, Int, Buffer from, Buffer to)
saner CodeBuffer from to
code Buffer from
ibuf Buffer to
obuf = do
(why, ibuf', obuf') <- CodeBuffer from to
code Buffer from
ibuf Buffer to
obuf
if isEmptyBuffer ibuf'
then return (InputUnderflow, bufferElems ibuf, ibuf', obuf')
else return (why, bufL ibuf' - bufL ibuf, ibuf', obuf')
byteView :: Buffer CWchar -> Buffer Word8
byteView :: Buffer CWchar -> Buffer Word8
byteView (Buffer {Int
Word64
RawBuffer CWchar
BufferState
bufL :: forall e. Buffer e -> Int
bufRaw :: RawBuffer CWchar
bufState :: BufferState
bufSize :: Int
bufOffset :: Word64
bufL :: Int
bufR :: Int
bufR :: forall e. Buffer e -> Int
bufOffset :: forall e. Buffer e -> Word64
bufSize :: forall e. Buffer e -> Int
bufState :: forall e. Buffer e -> BufferState
bufRaw :: forall e. Buffer e -> RawBuffer e
..}) = Buffer { bufState :: BufferState
bufState = BufferState
bufState, bufRaw :: RawBuffer Word8
bufRaw = RawBuffer CWchar -> RawBuffer Word8
forall a b. ForeignPtr a -> ForeignPtr b
castForeignPtr RawBuffer CWchar
bufRaw, bufSize :: Int
bufSize = Int
bufSize Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
2, bufOffset :: Word64
bufOffset = Word64
bufOffset, bufL :: Int
bufL = Int
bufL Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
2, bufR :: Int
bufR = Int
bufR Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
2 }
cwcharView :: Buffer Word8 -> Buffer CWchar
cwcharView :: Buffer Word8 -> Buffer CWchar
cwcharView (Buffer {Int
Word64
RawBuffer Word8
BufferState
bufL :: forall e. Buffer e -> Int
bufR :: forall e. Buffer e -> Int
bufOffset :: forall e. Buffer e -> Word64
bufSize :: forall e. Buffer e -> Int
bufState :: forall e. Buffer e -> BufferState
bufRaw :: forall e. Buffer e -> RawBuffer e
bufRaw :: RawBuffer Word8
bufState :: BufferState
bufSize :: Int
bufOffset :: Word64
bufL :: Int
bufR :: Int
..}) = Buffer { bufState :: BufferState
bufState = BufferState
bufState, bufRaw :: RawBuffer CWchar
bufRaw = RawBuffer Word8 -> RawBuffer CWchar
forall a b. ForeignPtr a -> ForeignPtr b
castForeignPtr RawBuffer Word8
bufRaw, bufSize :: Int
bufSize = Int -> Int
forall {a}. Integral a => a -> a
half Int
bufSize, bufOffset :: Word64
bufOffset = Word64
bufOffset, bufL :: Int
bufL = Int -> Int
forall {a}. Integral a => a -> a
half Int
bufL, bufR :: Int
bufR = Int -> Int
forall {a}. Integral a => a -> a
half Int
bufR }
where half :: a -> a
half a
x = case a
x a -> a -> (a, a)
forall a. Integral a => a -> a -> (a, a)
`divMod` a
2 of (a
y, a
0) -> a
y
(a, a)
_ -> String -> a
forall a. String -> a
errorWithoutStackTrace String
"cwcharView: utf16_(encode|decode) (wrote out|consumed) non multiple-of-2 number of bytes"
utf16_native_encode :: CodeBuffer Char CWchar
utf16_native_encode :: CodeBuffer CharBufElem CWchar
utf16_native_encode Buffer CharBufElem
ibuf Buffer CWchar
obuf = do
(why, ibuf, obuf) <- CodeBuffer CharBufElem Word8
utf16_native_encode' Buffer CharBufElem
ibuf (Buffer CWchar -> Buffer Word8
byteView Buffer CWchar
obuf)
return (why, ibuf, cwcharView obuf)
utf16_native_decode :: CodeBuffer CWchar Char
utf16_native_decode :: CodeBuffer CWchar CharBufElem
utf16_native_decode Buffer CWchar
ibuf Buffer CharBufElem
obuf = do
(why, ibuf, obuf) <- CodeBuffer Word8 CharBufElem
utf16_native_decode' (Buffer CWchar -> Buffer Word8
byteView Buffer CWchar
ibuf) Buffer CharBufElem
obuf
return (why, cwcharView ibuf, obuf)
cpDecode :: Word32 -> Int -> DecodeBuffer
cpDecode :: Word32 -> Int -> CodeBuffer Word8 CharBufElem
cpDecode Word32
cp Int
max_char_size = \Buffer Word8
ibuf Buffer CharBufElem
obuf -> do
#if defined(CHARBUF_UTF16)
let mbuf = obuf
#else
let sz :: Int
sz = (Buffer Word8 -> Int
forall e. Buffer e -> Int
bufferElems Buffer Word8
ibuf Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
2)
Int -> Int -> Int
forall a. Ord a => a -> a -> a
`min` (Buffer CharBufElem -> Int
forall e. Buffer e -> Int
bufferAvailable Buffer CharBufElem
obuf Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
2)
mbuf <- Int -> Int -> BufferState -> IO (Buffer CWchar)
forall e. Int -> Int -> BufferState -> IO (Buffer e)
newBuffer (Int
2 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
sz) Int
sz BufferState
WriteBuffer :: IO (Buffer CWchar)
#endif
debugIO $ "cpDecode " ++ summaryBuffer ibuf ++ " " ++ summaryBuffer mbuf
(why1, ibuf', mbuf') <- cpRecode try' is_valid_prefix max_char_size 1 0 1 ibuf mbuf
debugIO $ "cpRecode (cpDecode) = " ++ show why1 ++ " " ++ summaryBuffer ibuf' ++ " " ++ summaryBuffer mbuf'
#if defined(CHARBUF_UTF16)
return (why1, ibuf', mbuf')
#else
debugIO $ "utf16_native_decode " ++ summaryBuffer mbuf' ++ " " ++ summaryBuffer obuf
(why2, target_utf16_count, mbuf', obuf) <- saner utf16_native_decode (mbuf' { bufState = ReadBuffer }) obuf
debugIO $ "utf16_native_decode = " ++ show why2 ++ " " ++ summaryBuffer mbuf' ++ " " ++ summaryBuffer obuf
case why2 of
CodingProgress
InputUnderflow | Buffer CWchar -> Bool
forall e. Buffer e -> Bool
isEmptyBuffer Buffer CWchar
mbuf' -> (CodingProgress, Buffer Word8, Buffer CharBufElem)
-> IO (CodingProgress, Buffer Word8, Buffer CharBufElem)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (CodingProgress
why1, Buffer Word8
ibuf', Buffer CharBufElem
obuf)
| Bool
otherwise -> String -> IO (CodingProgress, Buffer Word8, Buffer CharBufElem)
forall a. String -> a
errorWithoutStackTrace String
"cpDecode: impossible underflown UTF-16 buffer"
CodingProgress
InvalidSequence -> String -> IO (CodingProgress, Buffer Word8, Buffer CharBufElem)
forall a. String -> a
errorWithoutStackTrace String
"InvalidSequence on output of Windows API"
CodingProgress
OutputUnderflow -> do
byte_count <- String
-> CodeBuffer Word8 CWchar
-> Buffer Word8
-> Buffer CWchar
-> Int
-> Int
-> Int
-> Int
-> IO Int
forall from to.
String
-> CodeBuffer from to
-> Buffer from
-> Buffer to
-> Int
-> Int
-> Int
-> Int
-> IO Int
bSearch String
"cpDecode" ((Ptr Word8 -> Int -> Ptr CWchar -> Int -> IO (Either Bool Int))
-> (Word8 -> IO Bool)
-> Int
-> Int
-> Int
-> Int
-> CodeBuffer Word8 CWchar
forall from to.
Storable from =>
(Ptr from -> Int -> Ptr to -> Int -> IO (Either Bool Int))
-> (from -> IO Bool)
-> Int
-> Int
-> Int
-> Int
-> CodeBuffer from to
cpRecode Ptr Word8 -> Int -> Ptr CWchar -> Int -> IO (Either Bool Int)
forall {a} {a} {b}.
(Integral a, Integral a, Show a, Show a, Num b) =>
Ptr Word8 -> a -> Ptr CWchar -> a -> IO (Either Bool b)
try' Word8 -> IO Bool
is_valid_prefix Int
max_char_size Int
1 Int
0 Int
1) Buffer Word8
ibuf Buffer CWchar
mbuf Int
target_utf16_count (Int
target_utf16_count Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
2) Int
target_utf16_count (Int
target_utf16_count Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
max_char_size)
return (OutputUnderflow, bufferRemove byte_count ibuf, obuf)
#endif
where
is_valid_prefix :: Word8 -> IO Bool
is_valid_prefix = Word32 -> Word8 -> IO Bool
c_IsDBCSLeadByteEx Word32
cp
try' :: Ptr Word8 -> a -> Ptr CWchar -> a -> IO (Either Bool b)
try' Ptr Word8
iptr a
icnt Ptr CWchar
optr a
ocnt
| a
ocnt a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
0 = Either Bool b -> IO (Either Bool b)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Bool -> Either Bool b
forall a b. a -> Either a b
Left Bool
True)
| Bool
otherwise = do
err <- Word32
-> Word32 -> Ptr Word8 -> CInt -> Ptr CWchar -> CInt -> IO CInt
c_MultiByteToWideChar (Word32 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word32
cp) Word32
8
Ptr Word8
iptr (a -> CInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
icnt) Ptr CWchar
optr (a -> CInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
ocnt)
debugIO $ "MultiByteToWideChar " ++ show cp ++ " 8 " ++ show iptr ++ " " ++ show icnt ++ " " ++ show optr ++ " " ++ show ocnt ++ "\n = " ++ show err
case err of
CInt
0 -> do
err <- IO Word32
getLastError
case err of
Word32
122 -> Either Bool b -> IO (Either Bool b)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Bool -> Either Bool b
forall a b. a -> Either a b
Left Bool
True)
Word32
1113 -> Either Bool b -> IO (Either Bool b)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Bool -> Either Bool b
forall a b. a -> Either a b
Left Bool
False)
Word32
_ -> String -> Word32 -> IO (Either Bool b)
forall a. String -> Word32 -> IO a
failWith String
"MultiByteToWideChar" Word32
err
CInt
wrote_chars -> Either Bool b -> IO (Either Bool b)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (b -> Either Bool b
forall a b. b -> Either a b
Right (CInt -> b
forall a b. (Integral a, Num b) => a -> b
fromIntegral CInt
wrote_chars))
cpEncode :: Word32 -> Int -> EncodeBuffer
cpEncode :: Word32 -> Int -> CodeBuffer CharBufElem Word8
cpEncode Word32
cp Int
_max_char_size = \Buffer CharBufElem
ibuf Buffer Word8
obuf -> do
#if defined(CHARBUF_UTF16)
let mbuf' = ibuf
#else
let sz :: Int
sz = (Buffer CharBufElem -> Int
forall e. Buffer e -> Int
bufferElems Buffer CharBufElem
ibuf Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
2)
Int -> Int -> Int
forall a. Ord a => a -> a -> a
`min` (Buffer Word8 -> Int
forall e. Buffer e -> Int
bufferAvailable Buffer Word8
obuf Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
2)
mbuf <- Int -> Int -> BufferState -> IO (Buffer CWchar)
forall e. Int -> Int -> BufferState -> IO (Buffer e)
newBuffer (Int
2 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
sz) Int
sz BufferState
WriteBuffer
(why1, ibuf', mbuf') <- utf16_native_encode ibuf mbuf
#endif
debugIO $ "\ncpEncode " ++ summaryBuffer mbuf' ++ " " ++ summaryBuffer obuf
(why2, target_utf16_count, mbuf', obuf) <- saner (cpRecode try' is_valid_prefix 2 1 1 0) (mbuf' { bufState = ReadBuffer }) obuf
debugIO $ "cpRecode (cpEncode) = " ++ show why2 ++ " " ++ summaryBuffer mbuf' ++ " " ++ summaryBuffer obuf
#if defined(CHARBUF_UTF16)
return (why2, mbuf', obuf)
#else
case why2 of
CodingProgress
InputUnderflow | Buffer CWchar -> Bool
forall e. Buffer e -> Bool
isEmptyBuffer Buffer CWchar
mbuf' -> (CodingProgress, Buffer CharBufElem, Buffer Word8)
-> IO (CodingProgress, Buffer CharBufElem, Buffer Word8)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (CodingProgress
why1, Buffer CharBufElem
ibuf', Buffer Word8
obuf)
| Bool
otherwise -> String -> IO (CodingProgress, Buffer CharBufElem, Buffer Word8)
forall a. String -> a
errorWithoutStackTrace String
"cpEncode: impossible underflown UTF-16 buffer"
CodingProgress
_ -> do
utf32_count <- String
-> CodeBuffer CharBufElem CWchar
-> Buffer CharBufElem
-> Buffer CWchar
-> Int
-> Int
-> Int
-> Int
-> IO Int
forall from to.
String
-> CodeBuffer from to
-> Buffer from
-> Buffer to
-> Int
-> Int
-> Int
-> Int
-> IO Int
bSearch String
"cpEncode" CodeBuffer CharBufElem CWchar
utf16_native_encode Buffer CharBufElem
ibuf Buffer CWchar
mbuf Int
target_utf16_count (Int
target_utf16_count Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
2) Int
target_utf16_count Int
target_utf16_count
return (why2, bufferRemove utf32_count ibuf, obuf)
#endif
where
is_valid_prefix :: p -> m Bool
is_valid_prefix p
_ = Bool -> m Bool
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False
try' :: Ptr CWchar -> a -> Ptr Word8 -> a -> IO (Either Bool b)
try' Ptr CWchar
iptr a
icnt Ptr Word8
optr a
ocnt
| a
ocnt a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
0 = Either Bool b -> IO (Either Bool b)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Bool -> Either Bool b
forall a b. a -> Either a b
Left Bool
True)
| Bool
otherwise = (Ptr Bool -> IO (Either Bool b)) -> IO (Either Bool b)
forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca ((Ptr Bool -> IO (Either Bool b)) -> IO (Either Bool b))
-> (Ptr Bool -> IO (Either Bool b)) -> IO (Either Bool b)
forall a b. (a -> b) -> a -> b
$ \Ptr Bool
defaulted_ptr -> do
Ptr Bool -> Bool -> IO ()
forall a. Storable a => Ptr a -> a -> IO ()
poke Ptr Bool
defaulted_ptr Bool
False
err <- Word32
-> Word32
-> Ptr CWchar
-> CInt
-> Ptr Word8
-> CInt
-> Ptr Word8
-> Ptr Bool
-> IO CInt
c_WideCharToMultiByte (Word32 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word32
cp) Word32
0
Ptr CWchar
iptr (a -> CInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
icnt) Ptr Word8
optr (a -> CInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
ocnt)
Ptr Word8
forall a. Ptr a
nullPtr Ptr Bool
defaulted_ptr
defaulted <- peek defaulted_ptr
debugIO $ "WideCharToMultiByte " ++ show cp ++ " 0 " ++ show iptr ++ " " ++ show icnt ++ " " ++ show optr ++ " " ++ show ocnt ++ " NULL " ++ show defaulted_ptr ++ "\n = " ++ show err ++ ", " ++ show defaulted
case err of
CInt
0 -> do
err <- IO Word32
getLastError
case err of
Word32
122 -> Either Bool b -> IO (Either Bool b)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Bool -> Either Bool b
forall a b. a -> Either a b
Left Bool
True)
Word32
1113 -> Either Bool b -> IO (Either Bool b)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Bool -> Either Bool b
forall a b. a -> Either a b
Left Bool
False)
Word32
_ -> String -> Word32 -> IO (Either Bool b)
forall a. String -> Word32 -> IO a
failWith String
"WideCharToMultiByte" Word32
err
CInt
wrote_bytes | Bool
defaulted -> Either Bool b -> IO (Either Bool b)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Bool -> Either Bool b
forall a b. a -> Either a b
Left Bool
False)
| Bool
otherwise -> Either Bool b -> IO (Either Bool b)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (b -> Either Bool b
forall a b. b -> Either a b
Right (CInt -> b
forall a b. (Integral a, Num b) => a -> b
fromIntegral CInt
wrote_bytes))
bSearch :: String
-> CodeBuffer from to
-> Buffer from -> Buffer to
-> Int
-> Int -> Int -> Int
-> IO Int
bSearch :: forall from to.
String
-> CodeBuffer from to
-> Buffer from
-> Buffer to
-> Int
-> Int
-> Int
-> Int
-> IO Int
bSearch String
msg CodeBuffer from to
code Buffer from
ibuf Buffer to
mbuf Int
target_to_elems = Int -> Int -> Int -> IO Int
go
where
go :: Int -> Int -> Int -> IO Int
go Int
mn Int
md Int
mx = do
(_why, ibuf, mbuf) <- CodeBuffer from to
code (Buffer from
ibuf { bufR = bufL ibuf + md }) Buffer to
mbuf
debugIO $ "code (bSearch " ++ msg ++ ") " ++ show md ++ " = " ++ show _why ++ ", " ++ summaryBuffer ibuf ++ summaryBuffer mbuf
case bufferElems mbuf `compare` target_to_elems of
Ordering
EQ -> String -> IO ()
debugIO (String
"bSearch = " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
solution) IO () -> IO Int -> IO Int
forall a b. IO a -> IO b -> IO b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Int -> IO Int
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Int
solution
where solution :: Int
solution = Int
md Int -> Int -> Int
forall a. Num a => a -> a -> a
- Buffer from -> Int
forall e. Buffer e -> Int
bufferElems Buffer from
ibuf
Ordering
LT -> Int -> Int -> IO Int
go' (Int
mdInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1) Int
mx
Ordering
GT -> Int -> Int -> IO Int
go' Int
mn (Int
mdInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
1)
go' :: Int -> Int -> IO Int
go' Int
mn Int
mx | Int
mn Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
mx = Int -> Int -> Int -> IO Int
go Int
mn (Int
mn Int -> Int -> Int
forall a. Num a => a -> a -> a
+ ((Int
mx Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
mn) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
2)) Int
mx
| Bool
otherwise = String -> IO Int
forall a. String -> a
errorWithoutStackTrace (String -> IO Int) -> String -> IO Int
forall a b. (a -> b) -> a -> b
$ String
"bSearch(" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
msg String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"): search crossed! " String -> String -> String
forall a. [a] -> [a] -> [a]
++ (String, String, Int, Int, Int) -> String
forall a. Show a => a -> String
show (Buffer from -> String
forall a. Buffer a -> String
summaryBuffer Buffer from
ibuf, Buffer to -> String
forall a. Buffer a -> String
summaryBuffer Buffer to
mbuf, Int
target_to_elems, Int
mn, Int
mx)
cpRecode :: forall from to. Storable from
=> (Ptr from -> Int -> Ptr to -> Int -> IO (Either Bool Int))
-> (from -> IO Bool)
-> Int
-> Int
-> Int -> Int
-> CodeBuffer from to
cpRecode :: forall from to.
Storable from =>
(Ptr from -> Int -> Ptr to -> Int -> IO (Either Bool Int))
-> (from -> IO Bool)
-> Int
-> Int
-> Int
-> Int
-> CodeBuffer from to
cpRecode Ptr from -> Int -> Ptr to -> Int -> IO (Either Bool Int)
try' from -> IO Bool
is_valid_prefix Int
max_i_size Int
min_o_size Int
iscale Int
oscale = CodeBuffer from to
go
where
go :: CodeBuffer from to
go :: CodeBuffer from to
go Buffer from
ibuf Buffer to
obuf | Buffer from -> Bool
forall e. Buffer e -> Bool
isEmptyBuffer Buffer from
ibuf = (CodingProgress, Buffer from, Buffer to)
-> IO (CodingProgress, Buffer from, Buffer to)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (CodingProgress
InputUnderflow, Buffer from
ibuf, Buffer to
obuf)
| Buffer to -> Int
forall e. Buffer e -> Int
bufferAvailable Buffer to
obuf Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
min_o_size = (CodingProgress, Buffer from, Buffer to)
-> IO (CodingProgress, Buffer from, Buffer to)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (CodingProgress
OutputUnderflow, Buffer from
ibuf, Buffer to
obuf)
| Bool
otherwise = Int
-> (Int -> Bool -> IO (CodingProgress, Buffer from, Buffer to))
-> IO (CodingProgress, Buffer from, Buffer to)
try (Buffer from -> Int
forall e. Buffer e -> Int
bufferElems Buffer from
ibuf Int -> Int -> Int
forall a. Ord a => a -> a -> a
`min` ((Int
max_i_size Int -> Int -> Int
forall a. Num a => a -> a -> a
* Buffer to -> Int
forall e. Buffer e -> Int
bufferAvailable Buffer to
obuf) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
min_o_size)) Int -> Bool -> IO (CodingProgress, Buffer from, Buffer to)
seek_smaller
where
done :: a -> m (a, Buffer from, Buffer to)
done a
why = (a, Buffer from, Buffer to) -> m (a, Buffer from, Buffer to)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (a
why, Buffer from
ibuf, Buffer to
obuf)
seek_smaller :: Int -> Bool -> IO (CodingProgress, Buffer from, Buffer to)
seek_smaller Int
n Bool
longer_was_valid
| Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
1 = if Bool
longer_was_valid
then CodingProgress -> IO (CodingProgress, Buffer from, Buffer to)
forall {m :: * -> *} {a}.
Monad m =>
a -> m (a, Buffer from, Buffer to)
done CodingProgress
OutputUnderflow
else do byte <- Buffer from -> (Ptr from -> IO from) -> IO from
forall e a. Buffer e -> (Ptr e -> IO a) -> IO a
withBuffer Buffer from
ibuf ((Ptr from -> IO from) -> IO from)
-> (Ptr from -> IO from) -> IO from
forall a b. (a -> b) -> a -> b
$ \Ptr from
ptr -> Ptr from -> Int -> IO from
forall a. Storable a => Ptr a -> Int -> IO a
peekElemOff Ptr from
ptr (Buffer from -> Int
forall e. Buffer e -> Int
bufL Buffer from
ibuf)
valid_prefix <- is_valid_prefix byte
done (if valid_prefix && bufferElems ibuf < max_i_size then InputUnderflow else InvalidSequence)
| Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
2 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
max_i_size = Int
-> (Int -> Bool -> IO (CodingProgress, Buffer from, Buffer to))
-> IO (CodingProgress, Buffer from, Buffer to)
try (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) (\Int
pred_n Bool
pred_n_was_valid -> Int -> Bool -> IO (CodingProgress, Buffer from, Buffer to)
seek_smaller Int
pred_n (Bool
longer_was_valid Bool -> Bool -> Bool
|| Bool
pred_n_was_valid))
| let n' :: Int
n' = Int
n Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
2 = Int
-> (Int -> Bool -> IO (CodingProgress, Buffer from, Buffer to))
-> IO (CodingProgress, Buffer from, Buffer to)
try Int
n' (Int
-> Bool
-> Int
-> Bool
-> IO (CodingProgress, Buffer from, Buffer to)
post_divide Int
n' Bool
longer_was_valid)
post_divide :: Int
-> Bool
-> Int
-> Bool
-> IO (CodingProgress, Buffer from, Buffer to)
post_divide Int
_ Bool
_ Int
n Bool
True = Int -> Bool -> IO (CodingProgress, Buffer from, Buffer to)
seek_smaller Int
n Bool
True
post_divide Int
n' Bool
longer_was_valid Int
n Bool
False | Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
n' Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
max_i_size Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1 = Int
-> (Int -> Bool -> IO (CodingProgress, Buffer from, Buffer to))
-> IO (CodingProgress, Buffer from, Buffer to)
try (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) (Int
-> Bool
-> Int
-> Bool
-> IO (CodingProgress, Buffer from, Buffer to)
post_divide Int
n' Bool
longer_was_valid)
| Bool
otherwise = Int -> Bool -> IO (CodingProgress, Buffer from, Buffer to)
seek_smaller Int
n' Bool
longer_was_valid
try :: Int
-> (Int -> Bool -> IO (CodingProgress, Buffer from, Buffer to))
-> IO (CodingProgress, Buffer from, Buffer to)
try Int
n Int -> Bool -> IO (CodingProgress, Buffer from, Buffer to)
k_fail = Buffer from
-> (Ptr from -> IO (CodingProgress, Buffer from, Buffer to))
-> IO (CodingProgress, Buffer from, Buffer to)
forall e a. Buffer e -> (Ptr e -> IO a) -> IO a
withBuffer Buffer from
ibuf ((Ptr from -> IO (CodingProgress, Buffer from, Buffer to))
-> IO (CodingProgress, Buffer from, Buffer to))
-> (Ptr from -> IO (CodingProgress, Buffer from, Buffer to))
-> IO (CodingProgress, Buffer from, Buffer to)
forall a b. (a -> b) -> a -> b
$ \Ptr from
iptr -> Buffer to
-> (Ptr to -> IO (CodingProgress, Buffer from, Buffer to))
-> IO (CodingProgress, Buffer from, Buffer to)
forall e a. Buffer e -> (Ptr e -> IO a) -> IO a
withBuffer Buffer to
obuf ((Ptr to -> IO (CodingProgress, Buffer from, Buffer to))
-> IO (CodingProgress, Buffer from, Buffer to))
-> (Ptr to -> IO (CodingProgress, Buffer from, Buffer to))
-> IO (CodingProgress, Buffer from, Buffer to)
forall a b. (a -> b) -> a -> b
$ \Ptr to
optr -> do
ei_err_wrote <- Ptr from -> Int -> Ptr to -> Int -> IO (Either Bool Int)
try' (Ptr from
iptr Ptr from -> Int -> Ptr from
forall a b. Ptr a -> Int -> Ptr b
`plusPtr` (Buffer from -> Int
forall e. Buffer e -> Int
bufL Buffer from
ibuf Int -> Int -> Int
forall a. Bits a => a -> Int -> a
`shiftL` Int
iscale)) Int
n
(Ptr to
optr Ptr to -> Int -> Ptr to
forall a b. Ptr a -> Int -> Ptr b
`plusPtr` (Buffer to -> Int
forall e. Buffer e -> Int
bufR Buffer to
obuf Int -> Int -> Int
forall a. Bits a => a -> Int -> a
`shiftL` Int
oscale)) (Buffer to -> Int
forall e. Buffer e -> Int
bufferAvailable Buffer to
obuf)
debugIO $ "try " ++ show n ++ " = " ++ show ei_err_wrote
case ei_err_wrote of
Left Bool
True -> Int -> Bool -> IO (CodingProgress, Buffer from, Buffer to)
k_fail Int
n Bool
True
Left Bool
False -> Int -> Bool -> IO (CodingProgress, Buffer from, Buffer to)
k_fail Int
n Bool
False
Right Int
wrote_elts -> CodeBuffer from to
go (Int -> Buffer from -> Buffer from
forall e. Int -> Buffer e -> Buffer e
bufferRemove Int
n Buffer from
ibuf) (Buffer to
obuf { bufR = bufR obuf + wrote_elts })
#endif