module Database.VCache.VGetInit
( vgetInit
) where
import Data.Bits
import Foreign.Ptr
import Database.VCache.Types
import Database.VCache.VGetAux
vgetInit :: VGet ()
vgetInit =
readAddrBytes >>= \ nAddrBytes ->
if (0 == nAddrBytes) then return () else
VGet $ \ s ->
let bUnderflow = nAddrBytes > (vget_limit s `minusPtr` vget_target s) in
if bUnderflow then return eBadAddressRegion else
let pAddrs = vget_limit s `plusPtr` negate nAddrBytes in
let sAddrs = s { vget_target = pAddrs } in
_vget readAddrs sAddrs >>= \ mbAddrs ->
case mbAddrs of
VGetR addrs _ ->
let s' = s { vget_children = addrs, vget_limit = pAddrs } in
return (VGetR () s')
VGetE eMsg -> return (VGetE eMsg)
eBadAddressRegion :: VGetR a
eBadAddressRegion = VGetE "VGet: failed to read address region"
readAddrBytes :: VGet Int
readAddrBytes = readAddrBytes' 0
readAddrBytes' :: Int -> VGet Int
readAddrBytes' !nAccum =
getWord8FromEnd >>= \ w8 ->
let nAccum' = (nAccum `shiftL` 7) .|. (fromIntegral (0x7f .&. w8)) in
if (w8 < 0x80) then return $! nAccum' else
readAddrBytes' nAccum'
readAddrs :: VGet [Address]
readAddrs =
getVarNat >>= \ nFirst ->
let addr0 = fromIntegral nFirst in
addr0 `seq` readAddrs' [addr0] nFirst
readAddrs' :: [Address] -> Integer -> VGet [Address]
readAddrs' addrs !nLast =
isEmpty >>= \ bEmpty ->
if bEmpty then return addrs else
getVarInt >>= \ nOff ->
let nCurr = nLast + nOff in
let addr = fromIntegral nCurr in
addr `seq` readAddrs' (addr:addrs) nCurr