packages feed

data-pdf-fieldreader-0.1.0.0: src/Data/Pdf/FieldReader.hs

{- |
Copyright: (c) 2021 Scott Sedgwick
SPDX-License-Identifier: MIT
Maintainer: Scott Sedgwick <scott.sedgwick@gmail.com>
Stability: experimental
Portability: unknown

Simple function to extract PDF form field values from a PDF file.
-}

module Data.Pdf.FieldReader
  ( -- * File data parser
    --
    -- $fileDataParser
    readPdfFields
  ) where

import Prelude hiding (drop, init, lines)
import Data.ByteString (ByteString)
import Data.ByteString.Char8 (unpack)
import Data.List (foldl')
import Data.Map (Map, fromList)
import Data.Text (Text, drop, init, isPrefixOf, lines, pack, replace, strip)

-- $fileDataParser
-- 
-- Extract a Map of name-value pairs from the data read from a PDF file.
-- For example:
--
-- >import qualified Data.ByteString as B
-- >import Data.Pdf.FieldReader (readPdfFields)
-- >
-- >main :: IO()
-- >main = do
-- >  xs <- Data.ByteString.readFile "filename"
-- >  let ys = readPdfFields xs
-- >  print ys

-- | Read fields from file data
readPdfFields :: ByteString -> Map Text Text
readPdfFields = fromList . snd . foldl' f (Nothing, []) . lines . pack . unpack
  where
    f (Nothing,  b) x | isFldName x  = (Just (fmtFldName x), b) 
                      | otherwise    = (Nothing, b)
    f ((Just n), b) x | isFldName x  = (Just (fmtFldName x), b)
                      | isFldValue x = (Nothing, (n, (fmtFldValue x)) : b)
                      | otherwise    = ((Just n), b)
    isFldName     = isPrefixOf "/T("
    fmtFldName    = stripBrackets
    isFldValue    = isPrefixOf "/V("
    fmtFldValue   = unescape . stripBrackets
    stripBrackets = init . drop 3 . strip
    unescape xs   = foldr (\(a, b) c -> replace a b c) xs escPairs
    escPairs      = [("\\n", "\n"), ("\\(", "("), ("\\)", ")")]