module Graphics.Formats.Obj.ParserBits
(unsafeReadFloat,unsafeRFloat
,anyOf
,consumeWS,firstWord, bsWords,removeComments,parseName) where
import Foreign
import Foreign.C.String
import Data.ByteString.Internal
import qualified Data.ByteString.Char8 as CBS
import qualified Data.ByteString.Unsafe as BS
import Data.Maybe
import Control.Applicative hiding ((<|>))
import Control.Applicative.Infix
unsafeReadFloat :: CBS.ByteString -> Float
unsafeReadFloat =
fst . maybe (error "unsafeReadFloat: No float to read.") id . unsafeRFloat
foreign import ccall unsafe "stdlib.h strtof"
c_strtof :: CString -> Ptr CString -> IO Float
unsafeRFloat :: ByteString -> Maybe (Float, ByteString)
unsafeRFloat b | CBS.null b = Nothing
unsafeRFloat b = inlinePerformIO $
alloca $ \resptr ->
BS.unsafeUseAsCString b $ \ptr ->
do
d <- c_strtof ptr resptr
newPtr <- peek resptr
return $! case d of
0 | newPtr == ptr -> Nothing
_ | otherwise ->
let rest = BS.unsafeDrop (newPtr `minusPtr` ptr) b
z = realToFrac d
in z `seq` rest `seq` Just $! (z, rest)
anyOf :: [a -> Bool] -> a -> Bool
anyOf = foldr (liftA2 (||)) (const False)
bsWords :: CBS.ByteString -> [CBS.ByteString]
bsWords =
filter ((>0) . CBS.length) . CBS.splitWith ((==' ') <^(||)^> (=='\t'))
removeComments :: CBS.ByteString -> CBS.ByteString
removeComments bs = case CBS.split '#' bs of
[] -> CBS.empty
(x:_) -> x
consumeWS :: CBS.ByteString -> CBS.ByteString
consumeWS = CBS.dropWhile ((==' ') <^(||)^> (=='\t'))
firstWord :: CBS.ByteString -> CBS.ByteString
firstWord = CBS.takeWhile (not . anyOf [(==' '), (=='\t'), (=='\n'), (=='\r')])
parseName :: CBS.ByteString -> CBS.ByteString
parseName = firstWord . consumeWS