diff options
Diffstat (limited to 'src/Data/BEncode/Internal.hs')
-rw-r--r-- | src/Data/BEncode/Internal.hs | 57 |
1 files changed, 40 insertions, 17 deletions
diff --git a/src/Data/BEncode/Internal.hs b/src/Data/BEncode/Internal.hs index e5ba89c..1532fe6 100644 --- a/src/Data/BEncode/Internal.hs +++ b/src/Data/BEncode/Internal.hs | |||
@@ -9,6 +9,7 @@ | |||
9 | -- don't need to import this module, use 'Data.BEncode' instead. | 9 | -- don't need to import this module, use 'Data.BEncode' instead. |
10 | -- | 10 | -- |
11 | {-# LANGUAGE MagicHash #-} | 11 | {-# LANGUAGE MagicHash #-} |
12 | {-# LANGUAGE CPP #-} | ||
12 | module Data.BEncode.Internal | 13 | module Data.BEncode.Internal |
13 | ( -- * Parsing | 14 | ( -- * Parsing |
14 | parser | 15 | parser |
@@ -26,12 +27,20 @@ import qualified Data.Attoparsec.ByteString.Char8 as P | |||
26 | import Data.ByteString as B | 27 | import Data.ByteString as B |
27 | import Data.ByteString.Internal as B (c2w, w2c) | 28 | import Data.ByteString.Internal as B (c2w, w2c) |
28 | import qualified Data.ByteString.Lazy as Lazy | 29 | import qualified Data.ByteString.Lazy as Lazy |
30 | #if MIN_VERSION_bytestring(0,10,0) | ||
29 | import qualified Data.ByteString.Lazy.Builder as B | 31 | import qualified Data.ByteString.Lazy.Builder as B |
30 | import qualified Data.ByteString.Lazy.Builder.ASCII as B | 32 | import qualified Data.ByteString.Lazy.Builder.ASCII as B |
33 | #else | ||
34 | import qualified Data.ByteString.Builder as B | ||
35 | -- import qualified Data.ByteString.Builder.ASCII as B | ||
36 | -- import qualified Data.ByteString.Builder.Internal as B | ||
37 | #endif | ||
31 | import Data.Foldable | 38 | import Data.Foldable |
32 | import Data.List as L | 39 | import Data.List as L |
33 | import Data.Monoid | 40 | import Data.Monoid |
34 | import Text.PrettyPrint hiding ((<>)) | 41 | import Text.PrettyPrint hiding ((<>)) |
42 | import Data.Char | ||
43 | import Data.Maybe | ||
35 | 44 | ||
36 | import Data.BEncode.Types | 45 | import Data.BEncode.Types |
37 | import Data.BEncode.BDict as BD | 46 | import Data.BEncode.BDict as BD |
@@ -74,6 +83,9 @@ builder = go | |||
74 | build :: BValue -> Lazy.ByteString | 83 | build :: BValue -> Lazy.ByteString |
75 | build = B.toLazyByteString . builder | 84 | build = B.toLazyByteString . builder |
76 | 85 | ||
86 | |||
87 | sample = "lld10:xOo@-ovQ\b}i8eeded12:]\ENQ89gJp\DC1Y\t!]17:\SOHRQ8\DLE\ESC\NULiUSRo\t.M<gei18eldede8:VX^ejm\SO_d12:.J*\DLEIc\SIV\ESCun\SOHdeede8:tg!\"lU\SOH\DEL1:Pe16:X\EMk\ESCGaek)\DC4'\t+\ESChhei-7e16:<OJ\v9\".i;\DC4[=]_D9de16:$-giCtwedm!\CAN\aA\DC3{dee" | ||
88 | |||
77 | {-------------------------------------------------------------------- | 89 | {-------------------------------------------------------------------- |
78 | -- Deserialization | 90 | -- Deserialization |
79 | --------------------------------------------------------------------} | 91 | --------------------------------------------------------------------} |
@@ -81,45 +93,56 @@ build = B.toLazyByteString . builder | |||
81 | -- TODO try to replace peekChar with something else | 93 | -- TODO try to replace peekChar with something else |
82 | -- | BEncode format parser according to specification. | 94 | -- | BEncode format parser according to specification. |
83 | parser :: Parser BValue | 95 | parser :: Parser BValue |
84 | parser = valueP | 96 | parser = valueP Nothing |
85 | where | 97 | where |
86 | valueP = do | 98 | valueP prior = do |
87 | mc <- P.peekChar | 99 | mc <- maybe (optional P.anyChar) (return . Just) prior |
88 | case mc of | 100 | case mc of |
89 | Nothing -> fail "end of input" | 101 | Nothing -> fail "end of input" |
90 | Just c -> | 102 | Just c -> |
91 | case c of | 103 | case c of |
92 | -- if we have digit it always should be string length | 104 | -- if we have digit it always should be string length |
93 | di | di <= '9' -> BString <$> stringP | 105 | di | '0' <= di && di <= '9' -> BString <$> stringP c |
94 | 'i' -> P.anyChar *> ((BInteger <$> integerP) <* P.anyChar) | 106 | 'i' -> ((BInteger <$> integerP) <* P.char 'e') -- P.anyChar) |
95 | 'l' -> P.anyChar *> ((BList <$> listBodyP) <* P.anyChar) | 107 | 'l' -> ((BList <$> listBodyP) ) -- <* P.anyChar) |
96 | 'd' -> P.anyChar *> (BDict <$> dictBodyP) <* P.anyChar | 108 | 'd' -> (BDict <$> dictBodyP) -- <* P.anyChar |
97 | t -> fail ("bencode unknown tag: " ++ [t]) | 109 | t -> fail ("bencode unknown tag: " ++ [t]) |
98 | 110 | ||
99 | dictBodyP :: Parser BDict | 111 | dictBodyP :: Parser BDict |
100 | dictBodyP = Cons <$> stringP <*> valueP <*> dictBodyP | 112 | dictBodyP = |
101 | <|> pure Nil | 113 | (P.char 'e' *> pure Nil) |
114 | <|> do c <- P.satisfy isDigit -- P.anyChar | ||
115 | Cons <$> stringP c <*> valueP Nothing <*> dictBodyP | ||
102 | 116 | ||
103 | listBodyP = do | 117 | listBodyP = do |
104 | c <- P.peekChar | 118 | c <- optional P.anyChar |
105 | case c of | 119 | case c of |
106 | Just 'e' -> return [] | 120 | Just 'e' -> return [] |
107 | _ -> (:) <$> valueP <*> listBodyP | 121 | _ -> (:) <$> valueP c <*> listBodyP |
108 | 122 | ||
109 | stringP :: Parser ByteString | 123 | leadingDigit c zeros n0 |
110 | stringP = do | 124 | | n0==(-10) = d * 10^(fromIntegral (B.length zeros)) |
111 | n <- P.decimal :: Parser Int | 125 | | n0/=0 = d * 10^(fromIntegral (B.length zeros) + truncate (1+logBase 10 (fromIntegral n0))) + n0 |
126 | | otherwise = d * 10 | ||
127 | where d = fromIntegral $ ord c - 48 | ||
128 | |||
129 | stringP :: Char -> Parser ByteString | ||
130 | stringP c = do | ||
131 | zeros <- P.takeWhile (=='0') | ||
132 | n0 <- (P.decimal <|> pure (-10)) :: Parser Int | ||
133 | let n = leadingDigit c zeros n0 | ||
112 | P.char ':' | 134 | P.char ':' |
113 | P.take n | 135 | P.take n |
114 | {-# INLINE stringP #-} | 136 | {-# INLINE stringP #-} |
115 | 137 | ||
116 | integerP :: Parser Integer | 138 | integerP :: Parser Integer |
117 | integerP = do | 139 | integerP = do |
118 | c <- P.peekChar | 140 | c <- optional P.anyChar |
119 | case c of | 141 | case c of |
120 | Just '-' -> do | 142 | Just '-' -> do |
121 | P.anyChar | ||
122 | negate <$> P.decimal | 143 | negate <$> P.decimal |
144 | Just c' -> do zeros <- P.takeWhile (=='0') | ||
145 | leadingDigit c' zeros <$> (P.decimal <|> pure (-10)) | ||
123 | _ -> P.decimal | 146 | _ -> P.decimal |
124 | {-# INLINE integerP #-} | 147 | {-# INLINE integerP #-} |
125 | 148 | ||