java.lang.Object
org.klomp.snark.bencode.BDecoder
Decodes a bencoded stream to
BEValues.A bencoded byte stream can represent byte arrays, numbers, lists and maps (dictionaries).
It also calculates, on request, the SHA-1 digest over the original bencoded bytes of the dictionary named "info", the info dictionary of a torrent. The info hash is defined as the digest of those bytes, which cannot be recomputed from the decoded map without re-encoding it byte for byte, so the bytes are hashed as they stream past.
Field Summary
FieldsModifier and TypeFieldDescriptionprivate intThe current nesting depth of lists and maps being decoded.private final InputStreamThe stream bencode is read from.private booleanTrue while the bytes being read belong to the info dictionary.private intThe last indicator read, zero if unknown: '0'..'9' indicates a byte[], 'i' a Number, 'l' a List, 'd' a Map, 'e' the end of a Number, List or Map (only used internally), and -1 the end of the stream.private static final intLargest byte array that may be allocated, to keep an attacker-controlled length from exhausting memory.private static final intDeepest nesting of lists and maps allowed, to stop a StackOverflowError on attacker-controlled input.private MessageDigestCreation deferred until we encounter the special map, to make processing of announce replies more efficient.private static final StringName of the dictionary whose bytes are hashed: the info dictionary of a torrent.Constructor Summary
ConstructorsMethod Summary
Modifier and TypeMethodDescriptionbdecode()Read the next indicator, returning null when the stream has ended, or bdecode the rest of the stream and returns the appropriate BEValue encoded object.static BEValuebdecode(InputStream in) Creates a new BDecoder and immediately decodes the first value it sees.Returns the next bencoded value on the stream and makes sure it is a byte array.Returns the next bencoded value on the stream and makes sure it is a list.Returns the next bencoded value on the stream and makes sure it is a map (dictionary).Returns the next bencoded value on the stream and makes sure it is a number.private voidStart hashing the info dictionary bytes.byte[]Returns the SHA-1 digest over the original bytes of the info dictionary, which is the torrent's info hash.intReturns what the next bencoded object will be on the stream, or -1 at end of stream.static voidPrints out the decoded data from a torrent file.private intread()Returns the next byte read from the InputStream.private byte[]read(int length) Reads the specified number of bytes from the InputStream.
Field Details
MAX_BYTE_ARRAY_LENGTH
private static final int MAX_BYTE_ARRAY_LENGTHLargest byte array that may be allocated, to keep an attacker-controlled length from exhausting memory.- See Also:
MAX_DEPTH
private static final int MAX_DEPTHDeepest nesting of lists and maps allowed, to stop a StackOverflowError on attacker-controlled input.- See Also:
in
The stream bencode is read from.indicator
private int indicatorThe last indicator read, zero if unknown: '0'..'9' indicates a byte[], 'i' a Number, 'l' a List, 'd' a Map, 'e' the end of a Number, List or Map (only used internally), and -1 the end of the stream. Call getNextIndicator to get the current value (it will never return zero).depth
private int depthThe current nesting depth of lists and maps being decoded.special_map
Name of the dictionary whose bytes are hashed: the info dictionary of a torrent.in_special_map
private boolean in_special_mapTrue while the bytes being read belong to the info dictionary.sha_digest
Creation deferred until we encounter the special map, to make processing of announce replies more efficient.
Constructor Details
BDecoder
Initializes a new BDecoder. Nothing is read from the given InputStream yet.- Parameters:
in- the InputStream to decode from
Method Details
get_special_map_digest
public byte[] get_special_map_digest()Returns the SHA-1 digest over the original bytes of the info dictionary, which is the torrent's info hash. Must be called after that dictionary has been decoded, and only once: the digest is finalized by this call.- Returns:
- the SHA-1 digest of the info dictionary bytes, or null if there was no info dictionary in the stream
bdecode
Creates a new BDecoder and immediately decodes the first value it sees.- Parameters:
in- the InputStream to decode from- Returns:
- the first BEValue on the stream, or null when the stream has ended
- Throws:
IOException- when something bad happens with the streamStackOverflowError- if the stream is nested too deeply to decodeThrowable
createDigest
private void createDigest()Start hashing the info dictionary bytes. Only the first info dictionary of a stream is hashed: a second one, which the spec does not allow, would make the digest wrong, and MetaInfo's constructor rejects the resulting info hash mismatch.getNextIndicator
Returns what the next bencoded object will be on the stream, or -1 at end of stream. Can return something unexpected when the stream isn't bencoded. This might or might not read one extra byte from the stream.- Returns:
- the next indicator character, or -1 at end of stream
- Throws:
IOException- if an I/O error occurs
bdecode
Read the next indicator, returning null when the stream has ended, or bdecode the rest of the stream and returns the appropriate BEValue encoded object.- Returns:
- the next BEValue on the stream, or null if the stream has ended
- Throws:
IOException- if an I/O error occurs or the stream is not bencodedStackOverflowError- if the stream is nested too deeply to decodeThrowable
bdecodeBytes
Returns the next bencoded value on the stream and makes sure it is a byte array. If it is not a bencoded byte array it will throw InvalidBEncodingException.- Returns:
- the next BEValue as a byte array
- Throws:
IOException- if an I/O error occursInvalidBEncodingException- if the next value is not a byte array
bdecodeNumber
Returns the next bencoded value on the stream and makes sure it is a number. If it is not a number it will throw InvalidBEncodingException.- Returns:
- the next BEValue as a Number
- Throws:
IOException- if an I/O error occursInvalidBEncodingException- if the next value is not a number
bdecodeList
Returns the next bencoded value on the stream and makes sure it is a list. If it is not a list it will throw InvalidBEncodingException.- Returns:
- the next BEValue as a List
- Throws:
IOException- if an I/O error occursInvalidBEncodingException- if the next value is not a listStackOverflowError- if the stream is nested too deeply to decodeThrowable
bdecodeMap
Returns the next bencoded value on the stream and makes sure it is a map (dictionary). If it is not a map it will throw InvalidBEncodingException.- Returns:
- the next BEValue as a Map
- Throws:
IOException- if an I/O error occursInvalidBEncodingException- if the next value is not a mapStackOverflowError- if the stream is nested too deeply to decodeThrowable
read
Returns the next byte read from the InputStream.- Returns:
- the next byte as an int (0-255)
- Throws:
EOFException- if end of stream is reachedIOException- if an I/O error occurs
read
Reads the specified number of bytes from the InputStream.- Parameters:
length- the number of bytes to read- Returns:
- a byte array containing the requested bytes
- Throws:
EOFException- if end of stream is reached before all bytes are readIOException- if an I/O error occurs
main
Prints out the decoded data from a torrent file.- Parameters:
args- command line arguments (expects one argument: the torrent file path)