diff options
Diffstat (limited to 'src/Data/Torrent')
-rw-r--r-- | src/Data/Torrent/Piece.hs | 26 |
1 files changed, 20 insertions, 6 deletions
diff --git a/src/Data/Torrent/Piece.hs b/src/Data/Torrent/Piece.hs index ea4e6253..bff6f948 100644 --- a/src/Data/Torrent/Piece.hs +++ b/src/Data/Torrent/Piece.hs | |||
@@ -41,17 +41,19 @@ module Data.Torrent.Piece | |||
41 | import Control.DeepSeq | 41 | import Control.DeepSeq |
42 | import Control.Lens | 42 | import Control.Lens |
43 | import qualified Crypto.Hash.SHA1 as SHA1 | 43 | import qualified Crypto.Hash.SHA1 as SHA1 |
44 | import Data.Aeson (ToJSON, FromJSON) | 44 | import Data.Aeson (ToJSON(..), FromJSON(..), Value(..), withText) |
45 | import Data.Aeson.TH | 45 | import Data.Aeson.TH |
46 | import Data.BEncode | 46 | import Data.BEncode |
47 | import Data.BEncode.Types | 47 | import Data.BEncode.Types |
48 | import Data.Bits | 48 | import Data.Bits |
49 | import Data.Bits.Extras | 49 | import Data.Bits.Extras |
50 | import Data.ByteString as BS | 50 | import Data.ByteString as BS |
51 | import qualified Data.ByteString.Lazy as BL | 51 | import qualified Data.ByteString.Lazy as BL |
52 | import qualified Data.ByteString.Base64 as Base64 | ||
52 | import Data.Char | 53 | import Data.Char |
53 | import Data.Int | 54 | import Data.Int |
54 | import Data.List as L | 55 | import Data.List as L |
56 | import Data.Text.Encoding as T | ||
55 | import Data.Typeable | 57 | import Data.Typeable |
56 | import Text.PrettyPrint | 58 | import Text.PrettyPrint |
57 | 59 | ||
@@ -127,11 +129,23 @@ ppPiece :: Piece a -> Doc | |||
127 | ppPiece Piece {..} | 129 | ppPiece Piece {..} |
128 | = "Piece" <+> braces ("index" <+> "=" <+> int pieceIndex) | 130 | = "Piece" <+> braces ("index" <+> "=" <+> int pieceIndex) |
129 | 131 | ||
132 | newtype HashArray = HashArray { unHashArray :: ByteString } | ||
133 | deriving (Show, Read, Eq, BEncode) | ||
134 | |||
135 | -- | Represented as base64 encoded JSON string. | ||
136 | instance ToJSON HashArray where | ||
137 | toJSON (HashArray bs) = String $ T.decodeUtf8 $ Base64.encode bs | ||
138 | |||
139 | instance FromJSON HashArray where | ||
140 | parseJSON = withText "HashArray" $ | ||
141 | either fail (return . HashArray) . Base64.decode . T.encodeUtf8 | ||
142 | |||
143 | -- | Part of torrent file used for torrent content validation. | ||
130 | data PieceInfo = PieceInfo | 144 | data PieceInfo = PieceInfo |
131 | { piPieceLength :: {-# UNPACK #-} !PieceSize | 145 | { piPieceLength :: {-# UNPACK #-} !PieceSize |
132 | -- ^ Number of bytes in each piece. | 146 | -- ^ Number of bytes in each piece. |
133 | 147 | ||
134 | , piPieceHashes :: !ByteString | 148 | , piPieceHashes :: !HashArray |
135 | -- ^ Concatenation of all 20-byte SHA1 hash values. | 149 | -- ^ Concatenation of all 20-byte SHA1 hash values. |
136 | } deriving (Show, Read, Eq, Typeable) | 150 | } deriving (Show, Read, Eq, Typeable) |
137 | 151 | ||
@@ -147,7 +161,7 @@ instance NFData PieceInfo | |||
147 | 161 | ||
148 | instance Lint PieceInfo where | 162 | instance Lint PieceInfo where |
149 | lint pinfo @ PieceInfo {..} | 163 | lint pinfo @ PieceInfo {..} |
150 | | BS.length piPieceHashes `rem` hashsize == 0 | 164 | | BS.length (unHashArray piPieceHashes) `rem` hashsize == 0 |
151 | , piPieceLength >= 0 = return pinfo | 165 | , piPieceLength >= 0 = return pinfo |
152 | | otherwise = Left undefined | 166 | | otherwise = Left undefined |
153 | 167 | ||
@@ -182,12 +196,12 @@ slice start len = BS.take len . BS.drop start | |||
182 | 196 | ||
183 | -- | Extract validation hash by specified piece index. | 197 | -- | Extract validation hash by specified piece index. |
184 | pieceHash :: PieceInfo -> PieceIx -> ByteString | 198 | pieceHash :: PieceInfo -> PieceIx -> ByteString |
185 | pieceHash PieceInfo {..} i = slice (hashsize * i) hashsize piPieceHashes | 199 | pieceHash PieceInfo {..} i = slice (hashsize * i) hashsize (unHashArray piPieceHashes) |
186 | 200 | ||
187 | -- | Find count of pieces in the torrent. If torrent size is not a | 201 | -- | Find count of pieces in the torrent. If torrent size is not a |
188 | -- multiple of piece size then the count is rounded up. | 202 | -- multiple of piece size then the count is rounded up. |
189 | pieceCount :: PieceInfo -> PieceCount | 203 | pieceCount :: PieceInfo -> PieceCount |
190 | pieceCount PieceInfo {..} = BS.length piPieceHashes `quot` hashsize | 204 | pieceCount PieceInfo {..} = BS.length (unHashArray piPieceHashes) `quot` hashsize |
191 | 205 | ||
192 | isLastPiece :: PieceInfo -> PieceIx -> Bool | 206 | isLastPiece :: PieceInfo -> PieceIx -> Bool |
193 | isLastPiece ci i = pieceCount ci == succ i | 207 | isLastPiece ci i = pieceCount ci == succ i |