module Geometry.Shapefile.ReadDbf ( readDbfFile,
readDbfData
) where
import Control.Monad (replicateM)
import Control.Monad.Loops (whileM)
import Data.Binary.Get hiding (getInt8)
import qualified Data.ByteString.Lazy as BL
import Geometry.Shapefile.Internal
import Geometry.Shapefile.Types
readDbfFile :: String -> IO DbfData
readDbfFile fp = readDbfData <$> BL.readFile fp
readDbfData :: BL.ByteString -> DbfData
readDbfData = runGet $ do
_ <- getByteString 4
numRecs <- getIntLE
firstRecPos <- getInt16LE
_ <- getByteString 22
let fieldsRemain = (< firstRecPos - 1) . fromIntegral <$> bytesRead
fields <- whileM fieldsRemain getDbfFieldDesc
_ <- getWord8
recs <- replicateM numRecs (getWord8 >> mapM getDbfRecord fields)
pure DbfData { dbfNumRecs = numRecs,
dbfFields = fields,
dbfRecords = recs }
getDbfFieldDesc :: Get DbfFieldDesc
getDbfFieldDesc = do
name <- getString 11
fieldT <- getCharVal
_ <- getIntLE
len <- getInt8
_ <- getByteString 15
pure DbfFieldDesc { fieldName = name,
fieldType = fieldT,
fieldLen = len }
getDbfRecord :: DbfFieldDesc -> Get DbfRecord
getDbfRecord field = let n = fieldLen field in
case fieldType field of
'C' -> DbfString <$> getString n
'N' -> DbfNum <$> getString n
_ -> DbfBS <$> getByteString n