{-# LINE 1 "System\\Win32\\WindowsString\\Types.hsc" #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE Trustworthy #-}
{-# LANGUAGE PackageImports #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE ViewPatterns #-}
module System.Win32.WindowsString.Types
( module System.Win32.WindowsString.Types
, module System.Win32.Types
) where
import System.Win32.Types hiding (
withTString
, withTStringLen
, peekTString
, peekTStringLen
, newTString
, failIf
, failIf_
, failIfNeg
, failIfNull
, failIfZero
, failIfFalse_
, failUnlessSuccess
, failUnlessSuccessOr
, errorWin
, failWith
, try
, withFilePath
, useAsCWStringSafe
)
import Foreign.C.Types (CUIntPtr(..))
import Foreign.C.String (CWString)
import qualified System.OsPath.Windows as WS
import System.OsPath.Windows (WindowsPath)
import System.OsString.Windows (decodeWith, encodeWith)
import System.OsString.Internal.Types
{-# LINE 53 "System\\Win32\\WindowsString\\Types.hsc" #-}
import "os-string" System.OsString.Encoding.Internal (decodeWithBaseWindows)
import qualified "os-string" System.OsString.Data.ByteString.Short.Word16 as SBS
import "os-string" System.OsString.Data.ByteString.Short.Word16 (
{-# LINE 61 "System\\Win32\\WindowsString\\Types.hsc" #-}
packCWString,
packCWStringLen,
useAsCWString,
useAsCWStringLen,
newCWString
)
import Data.Bifunctor (first)
import Data.Char (isSpace)
import Numeric (showHex)
import qualified System.IO as IO ()
import System.IO.Error (ioeSetErrorString)
import Foreign (allocaArray)
import Foreign.Ptr ( Ptr )
import Foreign.C.Error ( errnoToIOError )
import Control.Exception ( throwIO )
import qualified Control.Exception as EX
import GHC.Ptr (castPtr)
import GHC.IO.Exception
{-# LINE 83 "System\\Win32\\WindowsString\\Types.hsc" #-}
import GHC.IO.Encoding.UTF16 ( mkUTF16le )
import GHC.IO.Encoding.Failure ( CodingFailureMode(..) )
#include "windows_cconv.h"
withTString :: WindowsString -> (LPTSTR -> IO a) -> IO a
withFilePath :: WindowsPath -> (LPTSTR -> IO a) -> IO a
withTStringLen :: WindowsString -> ((LPTSTR, Int) -> IO a) -> IO a
peekTString :: LPCTSTR -> IO WindowsString
peekTStringLen :: (LPCTSTR, Int) -> IO WindowsString
newTString :: WindowsString -> IO LPCTSTR
withTString (WindowsString str) f = useAsCWString str (\ptr -> f (castPtr ptr))
withFilePath path = useAsCWStringSafe path
withTStringLen (WindowsString str) f = useAsCWStringLen str (\(ptr, len) -> f (castPtr ptr, len))
peekTString = fmap WindowsString . packCWString . castPtr
peekTStringLen = fmap WindowsString . packCWStringLen . first castPtr
newTString (WindowsString str) = fmap castPtr $ newCWString str
foreign import ccall unsafe "wchar.h wcslen" c_wcslen
:: CWString -> IO SIZE_T
useAsCWStringSafe :: WindowsPath -> (CWString -> IO a) -> IO a
useAsCWStringSafe wp@(WS path) f = useAsCWString path $ \(castPtr -> ptr) -> do
let len = SBS.numWord16 path
clen <- c_wcslen ptr
if clen == fromIntegral len
then f ptr
else do
path' <- either (const (_toStr wp)) id <$> (EX.try @IOException) (decodeWithBaseWindows path)
ioError (err path')
where
_toStr = fmap WS.toChar . WS.unpack
err path' =
IOError
{ ioe_handle = Nothing
, ioe_type = InvalidArgument
, ioe_location = "useAsCWStringSafe"
, ioe_description = "Windows filepaths must not contain internal NUL codepoints."
, ioe_errno = Nothing
, ioe_filename = Just path'
}
failIf :: (a -> Bool) -> String -> IO a -> IO a
failIf p wh act = do
v <- act
if p v then errorWin wh else return v
failIf_ :: (a -> Bool) -> String -> IO a -> IO ()
failIf_ p wh act = do
v <- act
if p v then errorWin wh else return ()
failIfNeg :: (Num a, Ord a) => String -> IO a -> IO a
failIfNeg = failIf (< 0)
failIfNull :: String -> IO (Ptr a) -> IO (Ptr a)
failIfNull = failIf (== nullPtr)
failIfZero :: (Eq a, Num a) => String -> IO a -> IO a
failIfZero = failIf (== 0)
failIfFalse_ :: String -> IO Bool -> IO ()
failIfFalse_ = failIf_ not
failUnlessSuccess :: String -> IO ErrCode -> IO ()
failUnlessSuccess fn_name act = do
r <- act
if r == 0 then return () else failWith fn_name r
failUnlessSuccessOr :: ErrCode -> String -> IO ErrCode -> IO Bool
failUnlessSuccessOr val fn_name act = do
r <- act
if r == 0 then return False
else if r == val then return True
else failWith fn_name r
errorWin :: String -> IO a
errorWin fn_name = do
err_code <- getLastError
failWith fn_name err_code
failWith :: String -> ErrCode -> IO a
failWith fn_name err_code = do
c_msg <- getErrorMessage err_code
msg <- either (fail . show) pure . decodeWith (mkUTF16le TransliterateCodingFailure) =<< if c_msg == nullPtr
then either (fail . show) pure . encodeWith (mkUTF16le TransliterateCodingFailure) $ "Error 0x" ++ Numeric.showHex err_code ""
else do msg <- peekTString c_msg
_ <- localFree c_msg
return msg
errno <- c_maperrno_func err_code
let msg' = reverse $ dropWhile isSpace $ reverse msg
ioerror = errnoToIOError fn_name errno Nothing Nothing
`ioeSetErrorString` msg'
throwIO ioerror
try :: String -> (LPTSTR -> UINT -> IO UINT) -> UINT -> IO WindowsString
try loc f n = do
e <- allocaArray (fromIntegral n) $ \lptstr -> do
r <- failIfZero loc $ f lptstr n
if (r > n) then return (Left r) else do
str <- peekTStringLen (lptstr, fromIntegral r)
return (Right str)
case e of
Left n' -> try loc f n'
Right str -> return str