packages feed

ginsu-0.8.2: Gale/Proto.hs

module Gale.Proto where

import Atom
import Data.Bits
import Data.Char
import GenUtil
import PackedString
import Gale.Puff
import SimpleParser
import System.Environment
import System.Time
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as LBS
import Data.Binary.Get
import Data.Word
import Control.Applicative ((<|>))


pubkey_magic3 :: [Word8]
pubkey_magic3 = map (fromIntegral . ord) "GALE\000\001"

decodeFragments :: [Word8] -> FragmentList
decodeFragments [] = []
decodeFragments xs = decodeFragment ft f : decodeFragments r where
    (ft,xs') = xdrReadUInt xs
    (fl,xs'') = xdrReadUInt xs'
    (f,r) = splitAt (fromIntegral fl) xs''

decodeFragment :: Word32 -> [Word8] -> (Atom, Fragment)
decodeFragment t xs = (fn,f t) where
    (fnl,xs') = xdrReadUInt xs
    (fn,xs'') = liftT2 (fromString . galeDecodeString,id) (splitAt (fromIntegral $ fnl * 2) xs')
    f 0 = FragmentText $ packString (galeDecodeString xs'')
    f 1 = FragmentData $ BS.pack  xs''
    f 2 = FragmentTime $ decodeTime xs''
    f 3 = FragmentInt (fromIntegral $ fst $ xdrReadUInt xs'')
    f 4 = FragmentNest (decodeFragments xs'')
    f x = error $ "unknown fragment: " ++ show x

decodeTime :: [Word8] -> ClockTime
decodeTime xs = TOD (fromIntegral t) 0 where
    (t,_) = xdrReadUInt (drop 4 xs)


parseNullString :: GenParser Word8 String
parseNullString = (sat (== 0) >> return "") <|> (parseSome 1 >>= \[x] -> fmap ((chr $ fromIntegral x):) parseNullString)

galeDecodeString :: [Word8] -> String
galeDecodeString [] = []
galeDecodeString (b1:b2:xs) = (chr $ (fromIntegral b2) .|. (fromIntegral b1 `shiftL` 8)) : galeDecodeString xs
galeDecodeString _ = error "invalid gale string"




xdrReadUInt :: [Word8] -> ( Word32,[Word8])
xdrReadUInt (b1:b2:b3:b4:bs) = (x,bs) where
    x = (fromIntegral b4) .|. (fromIntegral b3 `shiftL` 8) .|.
            (fromIntegral b2 `shiftL` 16) .|. (fromIntegral b1 `shiftL` 24)
xdrReadUInt bs = error $ "xdrReadUInt " ++ show bs

parseWord32 :: GenParser Word8 Word32
parseWord32 = do
    [b1,b2,b3,b4] <- parseSome 4
    return $ (fromIntegral b4) .|. (fromIntegral b3 `shiftL` 8) .|.
            (fromIntegral b2 `shiftL` 16) .|. (fromIntegral b1 `shiftL` 24)

parseLenData = parseWord32 >>= parseSome

parseIntegral32 :: Integral a => GenParser Word8 a
parseIntegral32 = fmap fromIntegral parseWord32

parseLenString :: GenParser Word8 String
parseLenString = do
    len <- parseIntegral32
    w <- parseSome (len * 2)
    return $ galeDecodeString w
{-
decodeTime (x:y:_) | x > 0 || y > 0 = endOfTime
decodeTime xs = TimeDiff {tdDay = 0, tdPicosec = 0, tdYear = 0, tdMonth = 0, tdHour = 0, tdMin = fromIntegral (t `div` 60) , tdSec = fromIntegral (t `mod` 60)} `addToClockTime` epoch where
    (t,_) = xdrReadUInt (drop 4 xs)

-}

getGaleDir :: IO String
getGaleDir = do
    gd <- GenUtil.lookupEnv "GALE_DIR"
    case gd of
        Just v -> return $ v ++ "/"
        Nothing -> do
            h <- getEnv "HOME"
            return (h ++ "/.gale/")

decodeFrags :: Get FragmentList
decodeFrags = df [] where
    df xs = do
        b <- isEmpty
        if b then return (reverse xs) else do
        z <- decodeFrag
        df (z:xs)

decodeFrag :: Get (Atom,Fragment)
decodeFrag = do
    ty <- getWord32be
    ln <- getWord32be
    fnl <- getWord32be
    fn <- replicateM (fromIntegral fnl) getWord16be
    let fn' = fromString (map (chr . fromIntegral) fn)
    let dl = fromIntegral $ ln - (4 + (fnl * 2))
    let x <+> y = x ++ " " ++ y
    fr <- case ty of
        0 -> do
            tx <- replicateM (dl `div` 2) getWord16be
            return $ FragmentText $ packString (map (chr . fromIntegral) tx)
        1 -> do
            --d <- bytes dl
            --d <- replicateM dl byte
            up <- getBytes dl
            return $ FragmentData up
        2 -> do
            w <- getWord64be
            skip 8 --word64
            return $ FragmentTime (TOD (fromIntegral w) 0)
        3 -> do
            w <- getWord32be
            return $ FragmentInt (fromIntegral w)
        4 -> do
            up <- getBytes dl
            return $ FragmentNest (runGet decodeFrags (LBS.fromChunks [up]))
        _ -> fail $ "unknown fragment type: " <+> show ty <+> show ln <+> show fnl <+> show fn'
    return (fn', fr)