content: -- ------------------------------------------------------------
  
  {- |
     Module     : Text.XML.HXT.IO.GetFILE
     Copyright  : Copyright (C) 2008 Uwe Schmidt
     License    : MIT
  
     Maintainer : Uwe Schmidt (uwe@fh-wedel.de)
     Stability  : stable
     Portability: portable
  
     The GET method for file protocol
  
  -}
  
  -- ------------------------------------------------------------
  
  module Text.XML.HXT.IO.GetFILE
      ( getStdinCont
      , getCont
      )
  
  where
  
  import           Control.Exception      ( try )
  
  import qualified Data.ByteString.Lazy   as B
  
  import           Network.URI            ( unEscapeString
                                          )
  import           System.IO.Error        ( ioeGetErrorString
                                          )
  import           System.Directory       ( doesFileExist
                                          -- , getPermissions
                                          -- , readable
                                          )
  import           Text.XML.HXT.DOM.XmlKeywords
  
  -- ------------------------------------------------------------
  
  getStdinCont            :: Bool -> IO (Either ([(String, String)], String) B.ByteString)
  getStdinCont strictInput
      = do
        c <- try ( do
                   cb <- B.getContents
                   if strictInput
                      then B.length cb `seq` return cb
                      else                   return cb
                 )
        return (either readErr Right c)
      where
      readErr e
          = Left ( [ (transferStatus,  "999")
                   , (transferMessage, msg)
                   ]
                 , msg
                 )
            where
            msg = "stdin read error: " ++ es
            es  = ioeGetErrorString e
  
  getCont         :: Bool -> String -> IO (Either ([(String, String)], String) B.ByteString)
  getCont strictInput source
      = do                        -- preliminary
        source'' <- checkFile source'
        case source'' of
             Nothing -> return $ fileErr "file not found"
             Just fn -> do
                        -- perm <- getPermissions fn  -- getPermission may fail
                        -- if not (readable perm)
                        if False
                           then return $ fileErr "file not readable"
                           else do
                                c <- try $
                                     do
                                     cb <- B.readFile fn
                                     if strictInput
                                        then B.length `seq` return cb
                                        else                return cb
                                return (either readErr Right c)
      where
      source' = drivePath $ source
      readErr e
          = fileErr (ioeGetErrorString e)
      fileErr msg0
          = Left ( [ (transferStatus,  "999")
                   , (transferMessage, msg)
                   ]
                 , msg
                 )
            where
            msg = "file read error: " ++ show msg0 ++ " when accessing " ++ show source'
  
      -- remove leading / if file starts with windows drive letter, e.g. /c:/windows -> c:/windows
      drivePath ('/' : file@(d : ':' : _more))
          | d `elem` ['A'..'Z'] || d `elem` ['a'..'z']
              = file
      drivePath file
          = file
  
  -- | check whether file exists, if not
  -- try to unescape filename and check again
  -- return the existing filename
  
  checkFile       :: String -> IO (Maybe String)
  checkFile fn
      = do
        exists <- doesFileExist fn
        if exists
           then return (Just fn)
           else do
                exists' <- doesFileExist fn'
                return ( if exists'
                         then Just fn'
                         else Nothing
                       )
      where
      fn' = unEscapeString fn
  
  -- ------------------------------------------------------------
  