packages feed

pdftotext-0.0.1.0: src/Pdftotext/Foreign.hs

{-# 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 = (>>= stringToText)

-- | Converts `std::string` into `Data.Text`.
stringToText :: StdString -> IO T.Text
stringToText ptr = do
  len <- fromIntegral <$> ffiStringLength ptr
  allocaBytes len \out ->
    ffiStringCopy ptr out
      >> T.peekCStringLen (out, len)
      <* ffiStringDelete ptr