{-# LANGUAGE BlockArguments #-}

{- ORMOLU_DISABLE -}
{-|
Module      : Pdftotext.Foreign
Description : Foreign interface
Copyright   : (c) 2020 G. Eyaeb
License     : BSD-3-Clause
Maintainer  : geyaeb@protonmail.com
Stability   : experimental
Portability : POSIX
-}
{- ORMOLU_ENABLE -}
module Pdftotext.Foreign
  ( -- * C++ objects
    Poppler_Document,
    Poppler_Page,

    -- * 'std::string' helper
    StdString,
    asText,
    stringToText,

    -- * FFI
    ffiOpenPdf,
    ffiOpenData,
    ffiDocumentDelete,
    ffiDocumentPages,
    ffiDocumentOpenPage,
    ffiPageDelete,
    ffiPageText,
    ffiStringLength,
    ffiStringDelete,
    ffiStringCopy,
  )
where

import qualified Data.Text as T
import qualified Data.Text.Foreign as T
import Foreign
import Foreign.C

data Poppler_Document

data Poppler_Page

data CStdString

type StdString = Ptr CStdString

foreign import ccall unsafe "poppler_document_open_pdf"
  ffiOpenPdf :: CString -> IO (Ptr Poppler_Document)

foreign import ccall unsafe "poppler_document_open_data"
  ffiOpenData :: Ptr Word8 -> CInt -> IO (Ptr Poppler_Document)

foreign import ccall unsafe "&poppler_document_delete"
  ffiDocumentDelete :: FunPtr (Ptr Poppler_Document -> IO ())

foreign import ccall unsafe "poppler_document_pages"
  ffiDocumentPages :: Ptr Poppler_Document -> IO CInt

foreign import ccall unsafe "poppler_document_open_page"
  ffiDocumentOpenPage :: Ptr Poppler_Document -> CInt -> IO (Ptr Poppler_Page)

foreign import ccall unsafe "&poppler_page_delete"
  ffiPageDelete :: FunPtr (Ptr Poppler_Page -> IO ())

foreign import ccall unsafe "poppler_page_text"
  ffiPageText :: Ptr Poppler_Page -> CBool -> IO StdString

foreign import ccall unsafe "string_get_length"
  ffiStringLength :: StdString -> IO CUInt

foreign import ccall unsafe "string_delete"
  ffiStringDelete :: StdString -> IO ()

foreign import ccall unsafe "string_copy"
  ffiStringCopy :: StdString -> Ptr CChar -> IO ()

-- | Converts `std::string` wrapped in IO into `Data.Text`.
asText :: IO StdString -> IO T.Text
asText :: IO StdString -> IO Text
asText = (IO StdString -> (StdString -> IO Text) -> IO Text
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= StdString -> IO Text
stringToText)

-- | Converts `std::string` into `Data.Text`.
stringToText :: StdString -> IO T.Text
stringToText :: StdString -> IO Text
stringToText ptr :: StdString
ptr = do
  Int
len <- CUInt -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (CUInt -> Int) -> IO CUInt -> IO Int
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> StdString -> IO CUInt
ffiStringLength StdString
ptr
  Int -> (Ptr CChar -> IO Text) -> IO Text
forall a b. Int -> (Ptr a -> IO b) -> IO b
allocaBytes Int
len \out :: Ptr CChar
out ->
    StdString -> Ptr CChar -> IO ()
ffiStringCopy StdString
ptr Ptr CChar
out
      IO () -> IO Text -> IO Text
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> CStringLen -> IO Text
T.peekCStringLen (Ptr CChar
out, Int
len)
      IO Text -> IO () -> IO Text
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* StdString -> IO ()
ffiStringDelete StdString
ptr