module Pdf.Toolbox.Core.IO.RIS
(
IS,
RIS(..),
RIS'(..),
seek,
size,
tell,
inputStream,
fromHandle,
fromHandle'
)
where
import Data.Int (Int64)
import Data.Functor
import Data.ByteString (ByteString)
import qualified Data.ByteString as BS
import Data.IORef
import System.IO
import System.IO.Streams (InputStream)
import qualified System.IO.Streams as Streams
type IS = InputStream ByteString
data RIS' = RIS' {
risSeek :: Int64 -> IO (IO (Maybe ByteString)),
risInputStream :: IS,
risPos :: IO Int64,
risSize :: Int64
}
newtype RIS = RIS (IORef RIS')
seek :: RIS -> Int64 -> IO ()
seek (RIS ref) pos = do
ris <- readIORef ref
source <- risSeek ris pos
stream <- Streams.makeInputStream source
(s, c) <- Streams.countInput stream
writeIORef ref ris {
risInputStream = s,
risPos = (+ pos) <$> c
}
fromHandle' :: Handle -> Int -> IO RIS
fromHandle' h buf = do
sz <- hFileSize h
posRef <- newIORef 0
stream <- Streams.makeInputStream (f posRef)
(s, c) <- Streams.countInput stream
RIS <$> newIORef RIS' {
risSeek = \pos -> do
hSeek h AbsoluteSeek (fromIntegral pos)
ref <- newIORef $ fromIntegral pos
return $ f ref,
risInputStream = s,
risPos = c,
risSize = fromIntegral sz
}
where
f ref = do
prevPos <- readIORef ref
curtPos <- hTell h
hSeek h AbsoluteSeek prevPos
chunk <- BS.hGetSome h buf
hSeek h AbsoluteSeek curtPos
writeIORef ref $! prevPos + fromIntegral (BS.length chunk)
return $! if BS.null chunk then Nothing else Just chunk
fromHandle :: Handle -> IO RIS
fromHandle h = fromHandle' h 32752
size :: RIS -> IO Int64
size (RIS ref) = risSize <$> readIORef ref
tell :: RIS -> IO Int64
tell (RIS ref) = readIORef ref >>= risPos
inputStream :: RIS -> IO IS
inputStream (RIS ref) = risInputStream <$> readIORef ref