BT文件快速解析算法

要想实现一个BT下载器,第一步就是解析bt文件:

d 
        8:announce 37:http://tracker.ktxp.com:6868/announce
        13:announce-list
        l
                l 37:http://tracker.ktxp.com:6868/announce e
                l 37:http://tracker.ktxp.com:7070/announce e
                l 36:udp://tracker.ktxp.com:6868/announce e
                l 36:udp://tracker.ktxp.com:7070/announce e
                l 37:http://tracker.dmhy.org:8000/announce e
                l 36:udp://tracker.dmhy.org:8000/announce e
                l 45:http://tracker.openbittorrent.com:80/announce e
                l 39:http://tracker.publicbt.com:80/announce e
                l 30:http://tracker.prq.to/announce e
                l 36:http://bt.titapark.com:2710/announce e
                l 33:http://bt.wiiyi.com:6969/announce e
                l 32:http://bt.dmzg.net:6969/announce e
                l 34:http://bt.levelup.cn:8080/announce e
                l 34:http://bt.levelup.cn:6060/announce e
                l 35:http://share.camoe.cn:8080/announce e
                l 38:http://tracker.dmguo.com:2710/announce e
                l 39:http://tracker.moeing.org:7070/announce e
                l 33:http://bt.popgo.net:7456/announce e 
        e
        
        10:created by          19:BitSpirit/3.6.0.362
        13:creation date      i  1274740582 e
        8:encoding              5:UTF-8
        4:info
                                        d 
                                                6:length                 i 113628312 e
                                                4:name                 35:[KTXP][KissXsis][08][GB][RV10].rmvb
                                                12:piece length     i 131072 e
                                                6:pieces                17340: (17340/20)个哈希值
                                         e

         5:nodes
         l
                l 15:125.201.115.115    i8873e      e
                l 14:188.222.12.177     i33323e     e
                l 15:122.116.183.140    i16844e     e
                l 14:60.241.239.181     i18362e     e
                l 14:109.204.140.41     i54067e     e
                l 13:91.126.201.30      i1066e        e
         e   //5:nodes
e  //对应文件开始的d
	
在https://tool.lu/torrent网站计算下info_hash
Hash	bbd1454a77291a4987759d4ef7029968870e6000

这个是我整理后的torrent文件,里面有很多信息,例如文件大小,片大小,片数和sha等等;

这个torrent文件采用的是B编码,里面主要就2种基本类型数据,一种是int类型,还有一种就是字符串

其他的有list和dictionary这个我们也按照基本类型数据来解析:

一些公共方法:

int get_digtal_length(int val)
{
	int ret=-1;
	
	if(val<10)
		return 1;
	
	ret=1;	
	while(val>10) //12	123
	{
		ret++;
		val/=10;	
	}
	
	//printf("get_digtal_length=%d\n",ret);
	
	return ret;
}

 

下面我们来看下解析integer类型的方法:


//content是bt文件拷贝到内存后的首地址
long get_key_value(const char *content,char *des_str,long offset,long *return_val)
{
	long read_value;
	char *new_offset;
	int stringlen;
	long tmp;
	char *p;
	
	stringlen=strlen(des_str);
	
	//6:lengthi113628312e
	if((new_offset=strstr(&content[offset],des_str)) != NULL)
	{		
		tmp=new_offset-content+stringlen;
		if(sscanf(&metafile_content[tmp],"i%lde",&read_value)==1)
		{
			//printf("\n**********get_key_value() new_offset=%d,read_value=%ld ***********\n",tmp,read_value);
			*return_val=read_value;
			return tmp; 
		}
		printf("\n********** get_key_value() cannot decode,wrong format!!! ***********\n");
		return -2;
	}
	printf("\n********** get_key_value() not found: %s ***********\n",des_str);
	*return_val=-1;
	return -1; 
}

解析字符串方法:

long get_key_string(const char *content,char *des_str,long offset,char *return_str)
{
	char *new_offset;
	int stringlen;
	int length;	//键值字符串的长度
	long tmp;
	
	stringlen=strlen(des_str);
	
	//printf("get_key_string() find strlen=%d\n",stringlen);
	
	//8:announce37:http://tracker.ktxp.com:6868/announce
	if((new_offset=strstr(metafile_content,des_str)) != NULL)
	{
		tmp=new_offset-metafile_content+stringlen;
		if(sscanf(&metafile_content[tmp],"%d:",&length)==1)
		{
			//printf("get_key_string() length=%d\n",length);
			memcpy(return_str,&metafile_content[tmp+get_digtal_length(length)+1],length);
			return_str[length]='\0';
			return  tmp;
		}
		printf("get_key_string() cannot decode,wrong format!!!\n");
		return -2; 
	}
	printf("\n**********get_key_string() not found: %s ***********\n",des_str);
	return -1; 
}

字符串list类型解析:

/****************************************************
13:announce-list
l
	l 37:http://tracker.ktxp.com:6868/announce e
	l 37:http://tracker.ktxp.com:7070/announce e
    ...
e
****************************************************/
int get_list(const char *content,const char *des_str,long offset)//,URL_t *url_list)
{
	char *new_offset;
	int stringlen,list_str_len;
	long tmp;
	int i,copyidx=0;
	
	stringlen=strlen(des_str);
	if((new_offset=strstr(&content[offset],des_str)) != NULL)
	{
		tmp=new_offset-content+stringlen;
		if(content[tmp++]!='l')
			return -2;
		
		while(content[tmp++]=='l')
		{
			if(sscanf(&metafile_content[tmp],"%d:",&list_str_len)==1)
			{
				tmp+=get_digtal_length(list_str_len)+1;
				memcpy((char *)url[copyidx],&metafile_content[tmp],list_str_len);
				url[copyidx][list_str_len]='\0';
			}
			copyidx++;
			tmp+=list_str_len+1;	//最后一个+1表示跳过e的意思
		}
#if 0	//debug		
		if(content[--tmp]=='e')
			printf("content[tmp]=='e'\n");
#endif			
		return copyidx;
	}
	return -1;
}

字符串列表改进版(动态分配):

//保存从torrent文件中获取到tracker的url
typedef struct _Announce_list {
	char    announce[128];
	struct _Announce_list  *next;
} Announce_list;

Announce_list *announce_list_head = NULL;


int dynamic_get_list(const char *content,const char *des_str,long offset)
{
	char *new_offset;
	int stringlen,list_str_len;
	long tmp;
	int i,cnt=0;
	Announce_list  *node = NULL;
	Announce_list  *p    = NULL;
	
	stringlen=strlen(des_str);
	if((new_offset=strstr(&content[offset],des_str)) != NULL)
	{
		tmp=new_offset-content+stringlen;
		if(content[tmp++]!='l')
			return -2;
		
		while(content[tmp++]=='l')
		{
			if(sscanf(&metafile_content[tmp],"%d:",&list_str_len)==1)
			{
				tmp+=get_digtal_length(list_str_len)+1;
				//过滤掉其他开头的tracker地址
				if( memcmp(&metafile_content[tmp],"http",4) == 0 ) {
					node = (Announce_list *)malloc(sizeof(Announce_list));
					memcpy(node->announce,&metafile_content[tmp],list_str_len);
					node->announce[list_str_len] = '\0';
					node->next = NULL;
					
					if(announce_list_head == NULL)
						announce_list_head = node;
					else {
						p = announce_list_head;
						while( p->next != NULL) 
							p = p->next; 
						p->next = node;
					}
					cnt++;					
				}
				
			}
			tmp+=list_str_len+1;	//+1 跳过e
		}
#if 0	//debug		
		if(content[--tmp]=='e')
			printf("content[tmp]=='e'\n");
#endif			
		return cnt;
	}
	return -1;
}

//打印链表
void print_list(Announce_list *list)
{
	Announce_list *p=list;
	
	if(p==NULL)
		return;
	
	while(p->next!=NULL)
	{
		printf("%s\n",p->announce);
		p=p->next;
	}	
	printf("\n");
}

每个pieces都有20Byte的sha1:

typedef char (*Hash_t)[20];
Hash_t hash_table,bank_hash_table;

//6:pieces17340:(17340/20)个哈希值
int get_has_array(const char *content,const char *des_str,long offset,int *pieces,Hash_t *hash)
{
	char *new_offset;
	int stringlen;
	long tmp;
	int hastable_length;
	int i;
	
	stringlen=strlen(des_str);
	
	if((new_offset=strstr(&content[offset],des_str)) != NULL)
	{
		tmp=new_offset-content+stringlen;
		if(sscanf(&metafile_content[tmp],"%d:",&hastable_length)==1)
		{
			*pieces=hastable_length;
			*hash=(Hash_t)malloc(hastable_length);
			
			printf("hash_addr=0x%p\n",*hash);	
			
			if(*hash!=NULL)
			{
				//printf("\n****get_has_array() malloc ok! \n\thastable_length=%ld,offset1=%d",hastable_length,tmp);
				tmp+=get_digtal_length(hastable_length)+1;
				//printf(",offset2=%d ***********\n",tmp);
				
				//for(i=0;i<16;i++)
				//	printf("%02X ",(unsigned char)metafile_content[tmp+i]);
				//printf("\n");
				memcpy((char *)*hash,&metafile_content[tmp],hastable_length);								
				return tmp;
			}
			return -3;
		}
		return -2;			
	}
	return -1;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值