-- Note: Some of these functions, when written in a point-free
-- style have a significant impact on the runtime speed of
-- unoptimised code, for example hGetPos contributes ~20% extra time

module Data.Binary.Raw(
    hGetInt, hPutInt,
    hGetByte, hPutByte, maxByte,
    hGetPos, hSetPos
    ) where

import System.IO
import Control.Monad
import Data.Bits
import Data.Word
import Data.Char


hGetPos :: Handle -> IO Integer
hGetPos hndl = hTell hndl

hSetPos :: Handle -> Integer -> IO ()
hSetPos hndl i = hSeek hndl AbsoluteSeek i


maxByte :: Word8
maxByte = 0xff

-- FROM the Binary module, thanks to the Hac 07 people!

hPutInt :: Handle -> Int -> IO ()
hPutInt hndl w32 = do
    let w4 = (w32 `shiftR` 24) .&. 0xff
        w3 = (w32 `shiftR` 16) .&. 0xff
        w2 = (w32 `shiftR`  8) .&. 0xff
        w1 =  w32              .&. 0xff
    hPutByte hndl w1
    hPutByte hndl w2
    hPutByte hndl w3
    hPutByte hndl w4

hPutByte :: Handle -> Int -> IO ()
hPutByte hndl i = hPutChar hndl $ chr i


hGetInt :: Handle -> IO Int
hGetInt hndl = do
    w1 <- hGetByte hndl
    w2 <- hGetByte hndl
    w3 <- hGetByte hndl
    w4 <- hGetByte hndl
    return $! (w4 `shiftL` 24) .|.
              (w3 `shiftL` 16) .|.
              (w2 `shiftL`  8) .|.
              (w1)


hGetByte :: Handle -> IO Int
hGetByte hndl = liftM ord $ hGetChar hndl