Commits

FlorianHartwig committed 3c412bc

First commit

Comments (0)

Files changed (4)

+syntax:glob
+*.hi
+*.o
+*.prof

src/Data/AttoBencode.hs

+{-# LANGUAGE OverloadedStrings #-}
+
+module Data.AttoBencode 
+    ( BValue(..) 
+    , Dict
+    , decode
+    , encode
+    ) where
+
+import qualified Data.ByteString.Char8 as B
+import Data.Bencode.Types
+import Data.Map (toAscList)
+import Data.Bencode.Parser
+import qualified Data.Map as M
+
+-- Encoding
+-- TODO: do this in a way that is not hilariously inefficient
+encode :: BValue -> B.ByteString
+encode (BString s) = B.concat [(B.pack . show . B.length) s, ":", s]
+encode (BInt n)    = B.pack ('i':show n) `B.snoc` 'e'
+encode (BList l)   = B.concat ["l", B.concat (map encode l), "e"]
+encode (BDict d)   = 
+    B.concat ["d", B.concat (map encodePair (toAscList d)), "e"]
+
+encodePair :: (B.ByteString, BValue) -> B.ByteString
+encodePair (key, value) = (encode (BString key)) `B.append` encode value
+
+-- testing
+testString, testInt, testDict, testList :: BValue
+testString = BString "Blabla"
+testInt = BInt 25
+testDict = BDict $ M.singleton "Blub" testInt
+testList = BList [testString, testInt]
+
+-- parse and re-encode torrent file, check that encoded string == parsed file
+testParser :: String -> IO ()
+testParser f =
+  do s <- B.readFile f
+     let r = decode s
+     case r of
+         Nothing -> return ()
+         Just t ->
+           do print $ encode t == s
+     return ()

src/Data/AttoBencode/Parser.hs

+{-# LANGUAGE BangPatterns #-}
+module Data.AttoBencode.Parser 
+    ( decode
+    , getList
+    , getDict
+    , getInteger
+    , bValue
+    ) where
+
+import Data.AttoBencode.Types
+import Prelude hiding (take)
+import Data.Attoparsec
+import Data.Attoparsec.Char8
+import Control.Applicative
+import Data.Map
+import qualified Data.ByteString as B
+
+-- TODO: replace using TH
+getString :: BValue -> B.ByteString
+getString (BString s) = s
+getString _           = error "Not a string"
+
+getInteger :: BValue -> Integer
+getInteger (BInt n) = n
+getInteger _        = error "Not an integer"
+
+getList :: BValue -> [BValue]
+getList (BList l) = l
+getList _         = error "Not a list"
+
+getDict :: BValue -> Dict
+getDict (BDict d) = d
+getDict _         = error "Not a dictionary"
+
+decode :: B.ByteString -> Maybe BValue
+decode = maybeResult . parse bValue
+
+bValue :: Parser BValue
+bValue = stringParser <|> intParser <|> listParser <|> dictParser
+
+bsParser :: Parser B.ByteString
+bsParser =
+ do l <- decimal
+    char ':'
+    take l
+{-# INLINE bsParser #-}
+
+stringParser :: Parser BValue
+stringParser = liftA BString bsParser
+{-
+intParser :: Parser BValue
+intParser =
+ do char 'i'
+    sign <- option '+' (char '-')
+    n <- decimal --TODO: signed instead?
+    char 'e'
+    return $ BInt $ if sign == '-' then -n else n
+-}
+intParser :: Parser BValue
+intParser = BInt <$> (char 'i' *> signed decimal <* char 'e')
+
+listParser :: Parser BValue
+listParser = BList <$> (char 'l' *> many bValue <* char 'e')
+
+pairParser :: Parser (B.ByteString, BValue)
+pairParser = 
+ do !key <- bsParser
+    !value <- bValue
+    return (key, value)
+
+dictParser :: Parser BValue
+dictParser = 
+ do char 'd'
+    !pairs <- many pairParser
+    char 'e'
+    return $ BDict $ fromList pairs -- TODO: fromAscList?

src/Data/AttoBencode/Types.hs

+module Data.AttoBencode.Types where
+
+import Data.Map
+import qualified Data.ByteString as B
+
+data BValue = BString !B.ByteString
+           | BInt !Integer
+           | BList ![BValue]
+           | BDict !Dict
+    deriving (Show, Eq)
+
+type Dict = Map B.ByteString BValue
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.