packages feed

libmagic-1.3.1: Magic/Utils.hsc

{- -*- Mode: haskell; -*-
Haskell magic Interface
Copyright (C) 2005 John Goerzen <jgoerzen@complete.org>

This code is under a 3-clause BSD license; see COPYING for details.
-}

{- |
   Module     : Magic.Utils
   Copyright  : Copyright (C) 2005 John Goerzen
   License    : BSD

   Maintainer : Joey Hess,
   Maintainer : id\@joeyh.name
   Stability  : provisional
   Portability: portable

Utils

Written by John Goerzen, jgoerzen\@complete.org
-}

module Magic.Utils (flaglist2int, fromMagicPtr, withMagicPtr, checkIntError,
                    throwErrorIfNull, decodeOsPath)
where

import Foreign
import Foreign.C.Error
import Foreign.C.String
import Magic.TypesLL
import Magic.Types
import Foreign.C.Types
import Control.Concurrent.MVar
import System.OsPath.Types
import System.OsString.Internal.Types
import System.OsString.Encoding
import Data.Type.Coercion
import qualified Data.ByteString.Short as SBS

flaglist2int :: [MagicFlag] -> CInt
flaglist2int mfl =
    foldl (\c f -> c .|. (fromIntegral . fromEnum $ f)) 0 mfl

fromMagicPtr :: String -> IO (Ptr CMagic) -> IO Magic
fromMagicPtr caller action =
    do ptr <- throwErrnoIfNull caller action
       m <- newForeignPtr magic_close ptr
       mvar <- newMVar m
       return (Magic mvar)

throwErrorIfNull :: String -> Ptr CMagic -> IO (Ptr a) -> IO (Ptr a)
throwErrorIfNull caller m action =
    do res <- action
       if res == nullPtr
          then throwError caller m
          else return res

withMagicPtr :: Magic -> (Ptr CMagic -> IO a) -> IO a
withMagicPtr (Magic mvar) a = withMVar mvar $ \m -> withForeignPtr m a

throwError :: String -> Ptr CMagic -> IO a
throwError caller cmagic =
               do errormsg <- magic_error cmagic
                  if errormsg /= nullPtr
                     then do em <- peekCString errormsg
                             fail $ caller ++ ": " ++ em
                     else fail $ caller ++ ": got error code but no error message"

checkIntError :: String -> Ptr CMagic -> IO CInt -> IO ()
checkIntError caller cmagic action = 
    do res <- action
       if res == 0
          then return ()
          else throwError caller cmagic

decodeOsPath :: OsPath -> IO (SBS.ShortByteString)
decodeOsPath p = case coercionToPlatformTypes of
    Right (_, co) -> return (getPosixString (coerceWith co p))
    -- libmagic built for windows with MinGW by eg
    -- https://github.com/nscaife/file-windows does not use
    -- wide bytes as are in WindowsString, so convert it using
    -- the locale encoding
    Left (_, co) ->
            encodeWithBasePosix' =<< decodeWithBaseWindows
                (getWindowsString (coerceWith co p))

foreign import ccall unsafe "magic.h &magic_close"
  magic_close :: FunPtr (Ptr CMagic -> IO ())

foreign import ccall unsafe "magic.h magic_error"
  magic_error :: Ptr CMagic -> IO CString