module Game.LambdaHack.Common.File
( encodeEOF, strictDecodeEOF, tryCreateDir, tryCopyDataFiles, appDataDir
) where
import qualified Codec.Compression.Zlib as Z
import qualified Control.Exception as Ex
import Control.Monad
import Data.Binary
import qualified Data.ByteString.Lazy as LBS
import qualified Data.Char as Char
import System.Directory
import System.Environment
import System.FilePath
import System.IO
encodeData :: Binary a => FilePath -> a -> IO ()
encodeData f a = do
let tmpPath = f <.> "tmp"
Ex.bracketOnError
(openBinaryFile tmpPath WriteMode)
(\h -> hClose h >> removeFile tmpPath)
(\h -> do
LBS.hPut h . Z.compress . encode $ a
hClose h
renameFile tmpPath f
)
encodeEOF :: Binary a => FilePath -> a -> IO ()
encodeEOF f a = encodeData f (a, "OK" :: String)
strictReadSerialized :: FilePath -> IO LBS.ByteString
strictReadSerialized f =
withBinaryFile f ReadMode $ \ h -> do
c <- LBS.hGetContents h
let d = Z.decompress c
LBS.length d `seq` return d
strictDecodeData :: Binary a => FilePath -> IO a
strictDecodeData = fmap decode . strictReadSerialized
strictDecodeEOF :: Binary a => FilePath -> IO a
strictDecodeEOF f = do
(a, n) <- strictDecodeData f
if n == ("OK" :: String)
then return $! a
else error $ "Fatal error: corrupted file " ++ f
tryCreateDir :: FilePath -> IO ()
tryCreateDir dir = do
dirExists <- doesDirectoryExist dir
unless dirExists $
Ex.handle (\(_ :: Ex.IOException) -> return ())
(createDirectory dir)
tryCopyDataFiles :: FilePath
-> (FilePath -> IO FilePath)
-> [(FilePath, FilePath)]
-> IO ()
tryCopyDataFiles dataDir pathsDataFile files =
let cpFile (fin, fout) = do
pathsDataIn <- pathsDataFile fin
bIn <- doesFileExist pathsDataIn
let pathsDataOut = dataDir </> fout
bOut <- doesFileExist pathsDataOut
when (not bOut && bIn) $
Ex.handle (\(_ :: Ex.IOException) -> return ())
(copyFile pathsDataIn pathsDataOut)
in mapM_ cpFile files
appDataDir :: IO FilePath
appDataDir = do
progName <- getProgName
let name = takeWhile Char.isAlphaNum progName
getAppUserDataDirectory name