# Written by Bram Cohen
# See license.txt for license information
# Filename: btfield. py btformats. py
# Btfield. py
# Code reading diary: 2004-9-1 Author:
# Pen: zfive5
# Note: This file is mainly used to convert bytes to bits.
# Function: converts bits of the List to byte.
# Parameter: 1 logical list, for example, [,]
# Return: byte stream, for example, 'A/x00'
# Effect:
#>>> Booleans_to_bitfield ([,])
# 'A'
#>>> Booleans_to_bitfield ([, 0])
# 'A/x00'
#
Def booleans_to_bitfield (booleans ):
R = []
For I in xrange (0, Len (booleans), 8 ):
V = 0
P = 0x80
For J in booleans [I: I + 8]:
If J:
V | = P
P> = 1
R. append (CHR (v ))
Return ''. Join (r)
# Function: converts the bitwise to byte streams to the bits list.
# Parameter: byte stream. The number of bytes is 'a/x00'
# Return: List of logical bits, for example, [false, true, true, false, true]
# Effect:
#>>> Bitfield_to_booleans ('A', 8)
# [False, true, true, false, true]
#
Def bitfield_to_booleans (bitfield, L ):
Extra = Len (bitfield) * 8-l
If extra <0 or extra> = 8:
Return none
R = []
For C in bitfield:
V = ord (c)
For I in xrange (8 ):
If V & 0x80! = 0:
R. append (true)
Else:
R. append (false)
V <= 1
If extra> 0:
If R [-extra:]! = [0] * extra:
Return none
Del R [-extra:]
Return R
# Function: Test 1
Def test_basic ():
X = [1, 1, 1, 0, 0, 0, 1, 1]
Y = [1, 1, 1, 0, 0, 0, 1, 1]
For a in [x, y, []:
Assert bitfield_to_booleans (booleans_to_bitfield (A), Len (A) =
# Function: Test 2
Def test_too_long ():
Assert bitfield_to_booleans ('AB', 8) = none
# Function: Test 3
Def test_too_short ():
Assert bitfield_to_booleans ('A', 9) = none
# Function: Test 4
Def test_nonzero_in_excess ():
Assert bitfield_to_booleans (CHR (0xff), 7) = none
# Written by Bram Cohen
# See license.txt for license information
# Btformats. py
From types import stringtype, longtype, inttype, listtype, dicttype
From re import compile
Reg = compile (R' ^ [^ //. ~] [^ //] * $ ')
Ints = [longtype, inttype]
# Function: Check whether the info information of the seed file is valid, including its subinformation,
# If an exception is thrown illegally, we can see from this file the INFO structure of the seed file.
# Info (dicttype ){
# 'Pipelineength ': ints (greater than zero ),
# 'Pieces': stringtype (Length: an integer multiple of 20 bytes ),
# 'Name': stringtype (cannot be non-file name characters such ),
# 'Length': ints (greater than zero, for a single file)
#}
#
# Info (dicttype ){
# 'Pipelineength ': ints (greater than zero ),
# 'Pieces': stringtype (Length: an integer multiple of 20 bytes ),
# 'Name': stringtype (cannot be non-file name characters such ),
# 'Files' (listtype ):[
# (Dicttype)
#{
# 'Length': ints (greater than zero)
# 'Path' (listtype): [(for example, "1", "2", "4.txt" stands for:"/1/2/4.txt"
# Stringtype,
# Stringtype,
# Stringtype,
#....
#]
#},
#
# (Dicttype)
{
# 'Length': ints (greater than zero)
# 'Path' (listtype ):[
# Stringtype,
# Stringtype,
# Stringtype,
#....
#]
#}
#....
#]
#}
#
# The sequence here may be that there are differences between the seed files
Def check_info (Info ):
If type (Info )! = Dicttype:
Raise valueerror, 'Bad metainfo-not a dictionary'
Pieces = info. Get ('pieces ')
If type (pieces )! = Stringtype or Len (pieces) % 20! = 0:
Raise valueerror, 'Bad metainfo-bad pieces key'
Piecelength = info. Get ('piece length ')
If type (piecelength) not in ints or piecelength <= 0:
Raise valueerror, 'Bad metainfo-illegal piece length'
Name = info. Get ('name ')
If type (name )! = Stringtype:
Raise valueerror, 'Bad metainfo-bad name'
If not Reg. Match (name ):
Raise valueerror, 'name % s disallowed for security reasons '% name
If Info. has_key ('files') = info. has_key ('length '):
Raise valueerror, 'single/multiple file Mix'
If Info. has_key ('length '):
Length = info. Get ('length ')
If type (length) not in ints or length <0:
Raise valueerror, 'Bad metainfo-bad length'
Else:
Files = info. Get ('files ')
If type (Files )! = Listtype:
Raise valueerror
For f in files:
If type (f )! = Dicttype:
Raise valueerror, 'Bad metainfo-bad file value'
Length = f. Get ('length ')
If type (length) not in ints or length <0:
Raise valueerror, 'Bad metainfo-bad length'
Path = f. Get ('path ')
If type (PATH )! = Listtype or Path = []:
Raise valueerror, 'Bad metainfo-bad Path'
For P in path:
If type (p )! = Stringtype:
Raise valueerror, 'Bad metainfo-bad path dir'
If not Reg. Match (P ):
Raise valueerror, 'path % s disallowed for security reasons '% P
For I in xrange (LEN (Files )):
For J in xrange (I ):
If files [I] ['path'] = files [J] ['path']:
Raise valueerror, 'Bad metainfo-duplicate Path'
# Function: Check whether the message of the seed file is valid, including its subinformation,
# If an exception is thrown illegally, we can see from this file the message structure of the seed file.
# This is the starting point of the seeds.
# Message (dicttype ){
# 'Info' (dicttype): {check_info (message. Get ('info') Same as above}
# 'Announce ': stringtype
#}
# The sequence here may be that there are differences between the seed files
Def check_message (Message ):
If type (Message )! = Dicttype:
Raise valueerror
Check_info (message. Get ('info '))
If type (message. Get ('announce '))! = Stringtype:
Raise valueerror
# Function: whether the message information is valid, including its subinformation. For this struct, I
# If you have not read any understandable information, enter the question mark ?????
# Message (dicttype ){
# 'Failure reason ': {check_info (message. Get ('info') Same as above}
# 'Peers' (listtype ):
#[
# (Dicttype)
#{
# 'IP': stringtype,
# 'Port': ints (greater than zero ),
# 'Peer id': stringtype (LEN (ID) = 20 here I guess Sha too)
#},
#
# (Dicttype)
#{
# 'IP': stringtype,
# 'Port': ints (greater than zero ),
# 'Peer id': stringtype (LEN (ID) = 20 here I guess Sha too)
#}
#...
#
#]
# 'Interval': ints (greater than zero ),
# 'Min interval': ints (greater than zero ),
# 'Tracker id': stringtype,
# 'Num peers': ints (greater than zero ),
# 'Done peers': ints (greater than zero ),
# 'Last': ints (greater than zero)
#}
# The order here may be that the actual order is not in or out
Def check_peers (Message ):
If type (Message )! = Dicttype:
Raise valueerror
If message. has_key ('failure reason '):
If type (Message ['failure reason '])! = Stringtype:
Raise valueerror
Return
Peers = message. Get ('peers ')
If type (peers )! = Listtype:
Raise valueerror
For P in peers:
If type (p )! = Dicttype:
Raise valueerror
If type (P. Get ('IP '))! = Stringtype:
Raise valueerror
Port = P. Get ('Port ')
If type (port) not in ints or P <= 0:
Raise valueerror
Id = P. Get ('peer id ')
If type (ID )! = Stringtype or Len (ID )! = 20:
Raise valueerror
Interval = message. Get ('interval', 1)
If type (interval) not in ints or interval <= 0:
Raise valueerror
MININT = message. Get ('min interval', 1)
If type (MININT) not in ints or MININT <= 0:
Raise valueerror
If type (message. Get ('tracker id ',''))! = Stringtype:
Raise valueerror
Npeers = message. Get ('num peers', 0)
If type (npeers) not in ints or npeers <0:
Raise valueerror
Dpeers = message. Get ('done peers', 0)
If type (dpeers) not in ints or dpeers <0:
Raise valueerror
Last = message. Get ('last', 0)
If type (last) not in ints or last <0:
Raise valueerror
# Here you will understand the structure of the BT seed file !!
# (To be continued)