- 性别
- 保密
- 积分
- 0
- 积分
- 74
- 精华
- 1
- 阅读权限
- 20
- 注册时间
- 2013-10-14
- 最后登录
- 2013-12-18
- 帖子
- 15
- 性别
- 保密
|
头文件
/**************************************************************************************************************
** 文件名: ResovlerMetafile.h
** 文件职能: 声明bt种子文件解析类,
** 创建日期: 2013-08-06
** 创建人: tmfish
****************************************************************************************************************/
#ifndef RESOLVERMETAFILE_H_
#define RESOLVERMETAFILE_H_
#define DEBUG
#include <iostream>
#include <cstdio>
#include <vector>
#include <string>
#include <cstring>
#include <cstdlib>
#include <fstream>
#include <cctype>
#include "sha1.h"
using namespace std;
typedef int FILETYPE; //文件类型
/*状态标识*/
typedef int STATE; //状态
const int NOFILE = 2; //文件为空
const int OK = 0; //成功标识
const int ERROR = -1; //错误标识
/*文件类型标识*/
const int ISSIMPLE =1; //单文件标识
const int ISMULTIPLE =2; //多文件标识
struct Files //多文件中的多个文件
{
int length; //单个文件的长度
char* path; //单个文件的路径及文件名
};
/****************************************************************************************************************
** 种子文件信息结构体
** 用于存储种子文件的主要信息
** 成员说明
flagFileType 标识文件是单文件还是多文件,
当其值为ISSIMPLE的时候表示单文件,所有的多文件特有属性(m_name,files,)失效
当其值为ISMULTIPLE的时候表示多文件,多有单文件特有属性失效(s_name,length)
pieceLen 指定piece的大小 通常为256KB、亦有128kb或512kb 单位为字节
pieces 每个piece对应hash值
file_name 单文件的文件名
fileLength 文件的总文件长度
dir_name 多文件存放所有文件的目录名称
multi_files 多文件中包含的所有文件的信息
tracker_list tracker地址列表,其类型为一个string类型的vector数组
第一个元素是主tracker地址
info_hash 根据info关键字的值计算的哈希值,固定为20字节
*****************************************************************************************************************/
typedef struct MetafileInfo
{
/*标识文件属性*/
int fileType;
/*单文件、多文件共有属性*/
long pieceLen; //每个piece的长度
char* pieces; //每个piece对应的hash值
long long fileLength; //文件总大小
vector<const char*> trackerList; //tracker地址列表
/*单文件特有属性*/
char* fileName; //文件名
/*多文件特有属性*/
char* dirName; //存放所有文件的文件夹名
vector<Files> multiFiles; //多文件中所有文件信息
unsigned char info_hash[20]; //根据info关键字的值计算的哈希值。
}* pMetaInfo;
/*种子文件解析类*/
class ResolverMetafile
{
public:
/*构造及析构函数*/
ResolverMetafile(string MetafilePath);
~ResolverMetafile();
/********************************************************************
*功能:获取共享文件信息
*返回:函数返回存储种子文件信息的m_metaInfo结构体对象
*参数:st_info是一个MetafileInfo类型的常引用,用于接收种子文件信息
存放点地址
*附注:该函数是文件解析类对外提供的主要接口
*********************************************************************/
MetafileInfo GetMetafileInfo(pMetaInfo*const ppst_info);
/*
* 功能:向tracker列表添加一个tracker服务器地址
* 返回:成功添加tracker返回1,tracker已经存在返回0
* 函数成功执行失败返回-1
* 参数:url指定添加的tracker地址,如果该地址存在与tracker
* 列表中,则函数退出
* 附注:当连接某些tarcker地址的时候,服务器会返回一个重定向地址,函数用于
* 添加该类地址,当调用该函数后,调用者应该重新调用GetMetafileInfo获取数据
*/
STATE AddTracker(const char* url);
protected:
/*
* 功能:更具info关键字的值计算其对应的哈希值,将其填充与m_metaInfo.info_hash内
* 返回:成功返回0,失败返回-1
* 附注:info关键字对应的值为一个字典。
*/
STATE CalcInfoHash();
/*
* 功能:读取m_metafilePath指定的种子文件,将文件内容保存到m_metafile中
* 返回:函数成功执行返回1,m_metafilePath为空返回2,失败返回-1
* 附注:文件读取方式为二进制读取
*/
STATE ReadMetafile();
/*
* 功能:判断种子文件类型
* 返回:单文件返回ISSIMPLE,多文件返回ISMULTIPLE,m_metafile为空返回2
* 附注:ISSIMPLE值为1,ISMULTIPLE值为2
*/
FILETYPE FileType();
/*
*功能:在m_metafile中查找指定关键字
*返回:函数查找到指定的关键字返回1,没有找到返回0,函数执行出错返回-1
*参数:word为需要查找的指定关键字,index为查找到的字符串的起始下标
*/
STATE FindWord(const char* word, long long& index);
/*
* 功能:解析种子文件的tracker服务器列表,将其放入m_metaInfo.trackerList
* 返回:函数成功执行返回0,失败返回-1
* 附注:m_metaInfo.trackerList第一个值为主tracker服务器
*/
STATE ResTracker();
/*
* 功能:解析piece快大小,将其放入m_metaInfo.pieceLen
* 返回:成功执行返回0,失败返回-1,m_metafile为空返回2
*/
STATE ResPieceLen();
/*
* 功能:解析每个块对应的hash值字符串,将其放入m_metaInfo.pieces
* 返回:函数成功执行返回0,失败返回-1,m_metafile为空返回2
*/
STATE ResPieces();
/*
* 功能:解析文件名,对于多文件而言解析目录名,
* 若解析单文件,放入m_metaInfo.filename,若解析多文件,放入dirName
* 返回:函数成功执行返回0,失败返回-1,m_metafile为空返回2
*/
STATE ResFileName();
/*
* 功能:解析总文件大小,填充m_metaInfo.fileLength
* 返回:函数成功执行返回0,失败返回-1,m_metafile为空返回2
*/
STATE ResFileLength();
/*
* 功能:解析文件大小和路径,仅对多文件有效,填充m_metaInfo.multiFiles结构体
* 返回:函数成功执行返回0,失败返回-1,m_metafile为空返回2
*/
STATE ResFilePathLen();
/*
* 功能:释放类资源
*/
void ReleaseMem();
protected:
/*种子文件信息*/
MetafileInfo m_metaInfo;
/*存储种子文件路径*/
string m_metafilePath;
/*存储种子文件的内容*/
unsigned char* m_metafile;
/*种子文件大小*/
long long int m_metafileLen;
#ifdef DEBUG
public:
/*测试函数*/
void Test();
#endif
};
#endif
---------------------------------------------------
源文件
-------------------------------------------------
/*
* resolvermetafile.cpp
* 对resolverMetafile类的具体实现
* Created on: 2013-8-6
* Author: tmfish
*/
#include "resolverMetafile.h"
#ifdef DEBUG
//测试函数
void ResolverMetafile::Test()
{
cout << "测试函数" << endl;
//合格测试
//*successful
cout << "filetype: " << m_metaInfo.fileType << endl;
cout << "piecelen: " << m_metaInfo.pieceLen << endl;
if (ISSIMPLE == m_metaInfo.fileType)
{
cout << "filename: " << m_metaInfo.fileName << endl;
}else if (ISMULTIPLE == m_metaInfo.fileType)
{
cout << "dirname: " << m_metaInfo.dirName << endl;
}
cout << "multiple files number: " << m_metaInfo.multiFiles.size() << endl;
for (int i=0; i<int(m_metaInfo.multiFiles.size()); i++)
{
cout << "path: " << m_metaInfo.multiFiles[i].path << endl;
cout << "length: " << m_metaInfo.multiFiles[i].length << endl;
}
cout << "fileLen: " << m_metaInfo.fileLength<< endl;
for(int i=0; i<int(m_metaInfo.trackerList.size()); i++)
{
cout << "trackerList" << i << ": " << m_metaInfo.trackerList[i] << endl;
}
cout << "test for add " << endl;
char url[] = "一个地址";
AddTracker(url);
for(int i=0; i<int(m_metaInfo.trackerList.size()); i++)
{
cout << "trackerList" << i << ": " << m_metaInfo.trackerList[i] << endl;
}
}
#endif
//构造函数
ResolverMetafile::ResolverMetafile(string path)
{
memset(&m_metaInfo, 0, sizeof(m_metaInfo));
m_metafile = NULL;
m_metafilePath = path;
m_metafileLen = 0;
ReadMetafile();
FileType();
ResTracker();
ResPieceLen();
ResPieces();
ResFileName();
ResFilePathLen();
ResFileLength();
CalcInfoHash();
}
//析构函数
ResolverMetafile::~ResolverMetafile()
{
/*某些释放*/
ReleaseMem();
}
/********************************************************************
*功能:获取共享文件信息
*返回:函数返回存储种子文件信息的m_metaInfo结构体对象
*参数:pst_info是一个MetafileInfo类型的指针的指针,用于接收种子文件信息
存放点地址
*********************************************************************/
MetafileInfo ResolverMetafile::GetMetafileInfo(pMetaInfo*const ppst_info)
{
*ppst_info = &m_metaInfo;
return m_metaInfo;
}
/*
* 功能:向tracker列表添加一个tracker服务器地址
* 返回:成功添加tracker返回1,tracker已经存在返回0
* 函数成功执行失败返回-1
* 参数:strTracker指定添加的tracker地址,如果该地址存在与tracker
* 列表中,则函数退出
* 附注:当连接某些tarcker地址的时候,服务器会返回一个重定向地址,函数用于
* 添加该类地址
*/
STATE ResolverMetafile::AddTracker(const char* url)
{
char* bufTmp = new char[strlen(url)+1];
memcpy(bufTmp,url,strlen(url)+1);
int size = m_metaInfo.trackerList.size();
//若地址存在,则无需添加
for (int i=0; i<size; i++)
{
if (0 == strcmp(m_metaInfo.trackerList.at(i),url))
{
return OK;
}
}
//于末尾追加元素
m_metaInfo.trackerList.push_back(bufTmp);
return OK;
}
/*
* 功能:判断种子文件类型
* 返回:单文件返回ISSIMPLE,多文件返回ISMULTIPLE,m_metafile为空返回2
* 附注:ISSIMPLE值为1,ISMULTIPLE值为2
*/
FILETYPE ResolverMetafile::FileType()
{
// cout << m_metafile << endl;
long long index;
//种子文件中files代表多文件
if (1 == FindWord("5:files",index))
{
m_metaInfo.fileType = ISMULTIPLE;
return ISMULTIPLE;
}else
{
m_metaInfo.fileType = ISSIMPLE;
return ISSIMPLE;
}
return ERROR;
}
/*
* 功能:读取m_metafilePath指定的种子文件,将文件内容保存到m_metafile中
* 返回:函数成功执行返回0,m_metafilePath为空返回2,失败返回-1
* 附注:文件读取方式为二进制读取
*/
STATE ResolverMetafile::ReadMetafile()
{
if (m_metafilePath.empty())
{
cerr << "文件路径为空!" << endl;
return ERROR;
}
/*
ifstream fin(m_metafilePath.c_str(), ios_base::in | ios_base::binary);
// fin.open("in");
if (!fin.is_open())
{
cerr<< "文件打开失败!" << endl;
return ERROR;
}
//获取种子文件长度
fin.seekg(0,ios::end);
m_metafileLen = fin.tellg();
m_metafile = new char[m_metafileLen+1];
// fin.read(m_metafile, m_metafileLen);]
fin >> m_metafile;
if (NULL == m_metafile)
{
cerr << "文件读取失败" << endl;
return ERROR;
}
m_metafile[m_metafileLen] = '\0';
cout << m_metafile[3] << endl;
fin.close();
*/
//以二进制、只读方式打开文件
FILE* fp = fopen(m_metafilePath.c_str(), "rb");
if (NULL == fp)
{
cout << "文件打开失败" << endl;
return -1;
}
//获取种子文件的长度,
fseek(fp, 0, SEEK_END);
m_metafileLen = ftell(fp);
if (-1 == m_metafileLen)
{
cout << "文件长度错误" << endl;
return -1;
}
m_metafile = new unsigned char[m_metafileLen+1];
if (NULL == m_metafile)
{
cout << "内存分配失败" << endl;
return -1;
}
//读取种子文件的内容到m_metafile
fseek(fp, 0, SEEK_SET);
long i;
for ( i=0; i<m_metafileLen; i++)
{
m_metafile[i] = fgetc(fp);
}
m_metafile[i] = '\0';
fclose(fp);
return OK;
}
/*
*功能:在m_metafile中查找指定关键字
*返回:函数查找到指定的关键字返回1,没有找到返回0,函数执行出错返回-1
*参数:word为需要查找的指定关键字,index为查找到的字符串的起始下标的引用
*/
STATE ResolverMetafile::FindWord(const char* word, long long& index)
{
if (NULL == m_metafile)
{
cerr << "种子内容为空" << endl;
return ERROR;
}
for (long long int i=0; i<(m_metafileLen-long(strlen(word))); i++)
{
if (0 == memcmp(&m_metafile[i], word, strlen(word)))
{
index = i;
return 1;
}
}
//未找到
return 0;
}
/*
* 功能:解析种子文件的tracker服务器列表,将其放入m_metaInfo.trackerList
* 返回:函数成功执行返回0,失败返回-1
* 附注:m_metaInfo.trackerList第一个值为主tracker服务器
*/
STATE ResolverMetafile::ResTracker()
{
if (NULL == m_metafile)
{
cerr << "种子内容为空" << endl;
return ERROR;
}
long long index = 0;
if (0 == FindWord("13:announce-list",index)) //单文件处理
{
if (1 == FindWord("8:annouce",index))
{
int len = 0; //tracker长度
index = index + strlen("8:announce"); //跳过"8:announce"
while (isdigit(m_metafile[index]))
{
len = len*10 + (m_metafile[index] - '0');
index++;
}
index ++; //跳过':'
//填充m_metaInfo.trackerList数据成员
char* tmpBuf = new char[len+1];
memcpy(tmpBuf, &m_metafile[index], len);
tmpBuf[len] = '\0';
if(!m_metaInfo.trackerList.empty())
{
m_metaInfo.trackerList.clear();
}
m_metaInfo.trackerList.push_back(tmpBuf);
}//end if
}else //如果有“13:announce-list”关键字,则不用处理"8:annoucne"关键字
{
index+=strlen("13:announce-list"); //跳过"13:announce-list"
index++;//跳过'l'
index++;//跳过'l'
int len = 0;
while('e' != m_metafile[index])
{
while(isdigit(m_metafile[index]))
{
len = len*10 + (m_metafile[index]-'0');
index++;
}
index++;//跳过':'
//提取tracker 放入m_metafile.trackerList容器
//只处理"http"开头的地址
if (0 == memcmp(&m_metafile[index],"http",4))
{
char* tmpBuf = new char[len+1];
memcpy(tmpBuf, &m_metafile[index], len);
tmpBuf[len] = '\0';
m_metaInfo.trackerList.push_back(tmpBuf);
}
//准备读取下一个tracker地址
index = index + len;
len =0;
} //end while 1
} //end if else
return OK;
}
/*
* 功能:解析piece快大小,将其放入m_metaInfo.pieceLen
* 返回:成功执行返回0,失败返回-1,m_metafile为空返回2
*/
STATE ResolverMetafile::ResPieceLen()
{
if (NULL == m_metafile)
{
cerr << "种子内容为空" << endl;
return ERROR;
}
m_metaInfo.pieceLen = 0;
long long index =0;
if (1 == FindWord("12:piece length", index))
{
index += strlen("12:piece length"); //跳过"12:piece length"
index ++; //跳过':'
//填充m_metaInfo.pieceLen
while(isdigit(m_metafile[index]))
{
m_metaInfo.pieceLen = 10*(m_metaInfo.pieceLen) + (m_metafile[index]-'0');
index++;
}
}else
{
return ERROR;
}
return OK;
}
/*
* 功能:解析每个块对应的hash值字符串,将其放入m_metaInfo.pieces
* 返回:函数成功执行返回0,失败返回-1,m_metafile为空返回2
*/
STATE ResolverMetafile::ResPieces()
{
if (NULL == m_metafile)
{
cerr << "种子内容为空" << endl;
return ERROR;
}
long long index = 0;
if (1 == FindWord("6:pieces", index))
{
index += strlen("6:pieces");
long len = 0;
while (isdigit(m_metafile[index]))
{
len = len*10 + (m_metafile[index]-'0');
index++;
}
//填充m_metaInfo.pieces
index++;//跳过':'
m_metaInfo.pieces = new char[len+1];
memcpy(m_metaInfo.pieces, &m_metafile[index], len);
m_metaInfo.pieces[len] = '\0';
}else
{
return ERROR;
}
return OK;
}
/*
* 功能:解析文件名,对于多文件而言解析目录名,
* 若解析单文件,放入m_metaInfo.filename,若解析多文件,放入dirName
* 返回:函数成功执行返回0,失败返回-1,m_metafile为空返回2
*/
STATE ResolverMetafile::ResFileName()
{
if (NULL == m_metafile)
{
cerr << "种子内容为空" << endl;
return ERROR;
}
long long index;
int count = 0;
if (1 == FindWord("4:name", index))
{
index = index + 6; //跳过'4:name'
while (':' != m_metafile[index] )
{
count = count*10+(m_metafile[index]-'0');
index++;
}
index++;//跳过':'
if (ISSIMPLE == m_metaInfo.fileType)
{
m_metaInfo.fileName = new char[count+1];
memcpy(m_metaInfo.fileName,&m_metafile[index], count);
m_metaInfo.fileName[count] ='\0';
}else if(ISMULTIPLE == m_metaInfo.fileType)
{
m_metaInfo.dirName = new char[count+1];
memcpy(m_metaInfo.dirName,&m_metafile[index], count);
m_metaInfo.dirName[count] ='\0';
}
}else
{
return ERROR;
}
return OK;
}
/*
* 功能:解析总文件大小,填充m_metaInfo.fileLength
* 返回:函数成功执行返回0,失败返回-1,m_metafile为空返回2
*/
STATE ResolverMetafile::ResFileLength()
{
if (NULL == m_metafile)
{
cerr << "种子内容为空" << endl;
return ERROR;
}
long long index = 0;
long long size = 0;
if (ISSIMPLE == m_metaInfo.fileType )
{
cout << "enter simple file process " << endl;
if (1 == FindWord("6:length",index)) //单文件
{
index = index+strlen("6:length"); //跳过"6:length"
index ++ ; //跳过'i'
while(isdigit(m_metafile[index]))
{
size = size*10 + (m_metafile[index]-'0');
index++;
}
m_metaInfo.fileLength = size;
} //end if
}else if(ISMULTIPLE == m_metaInfo.fileType)
{
for(int i=0; i<int(m_metaInfo.multiFiles.size()); i++)
{
m_metaInfo.fileLength = m_metaInfo.fileLength +
m_metaInfo.multiFiles[i].length;
}
}else
{
return ERROR;
}
return OK;
}
/*
* 功能:解析文件大小和路径,仅对多文件有效,填充m_metaInfo.multiFiles结构体
* 并将files填充,代表多文件的文件个数
* 返回:函数成功执行返回0,失败返回-1,m_metafile为空返回2
*/
STATE ResolverMetafile::ResFilePathLen()
{
if (NULL == m_metafile)
{
cerr << "种子内容为空" << endl;
return NOFILE;
}
//不是多文件该函数无效
if (ISMULTIPLE != m_metaInfo.fileType)
{
return ERROR;
}
int length = 0;
// char* path = NULL;
int pathSize = 0;
Files mfBuf ;
memset(&mfBuf, 0, sizeof(mfBuf));
for(long i=0; i<(m_metafileLen-8); i++) //-8预留空间,防内存溢出
{
//获取多文件中各个文件的大小
if (0 == memcmp(&m_metafile[i], "6:length", 8))
{
i+=8; //跳过"6:length"
i++; //跳过'i'
length = 0;
while('e' != m_metafile[i])
{
length = length*10 + (m_metafile[i]-'0');
i++;
}
mfBuf.length = length;
//填充m_metaInfo.multiFiles成员,于末尾追加
m_metaInfo.multiFiles.push_back(mfBuf);
}//end if
//获取多文件中文件路径
if (0 == memcmp(&m_metafile[i], "4:path", 4))
{
i+=6; //跳过"4:path"
i++; //跳过 'l'
pathSize = 0;
while(':' != m_metafile[i])
{
pathSize = pathSize*10 + (m_metafile[i] - '0');
i++;
}
i++; //跳过':'
//填充m_metaInfo.multiFiles成员,于末尾追加
int end = m_metaInfo.multiFiles.size();
(m_metaInfo.multiFiles[end-1]).path = new char[pathSize+1];
memcpy((m_metaInfo.multiFiles[end-1]).path, &m_metafile[i], pathSize);
(m_metaInfo.multiFiles[end-1]).path[pathSize] = '\0';
}//end if
} //end for
return OK;
}
/*
* 功能:更具info关键字的值计算其对应的哈希值,将其填充与m_metaInfo.info_hash内
* 返回:成功返回0,失败返回-1
* 附注:info关键字对应的值为一个字典。
*/
STATE ResolverMetafile::CalcInfoHash()
{
if (NULL == m_metafile)
{
cerr << "种子内容为空" << endl;
return NOFILE;
}
//begin 为info关键字值开始下标,end为结束
int push_pop = 0;
long long index=0,begin=0,end=0;
if (1 == FindWord("4:info", index))
{
begin = index+6;
}else
{
return ERROR;
}
index +=6; //跳过"4:info"
/*
* 核心算法: 遍历info关键字后的值,当遇到d,l时push_pop++,
* 如果遇到e,则push_pop--当push_pop为0的时候,
* 则证明info关键字后的字典结束,遇见i则直接遍历
* i的内容,遇见数字则直接计算其后字串内容
*/
for (;index<m_metafileLen;)
{
if ('d' == m_metafile[index])
{
push_pop++;
index++;
}else if ('l' == m_metafile[index])
{
push_pop++;
index++;
}else if ('i' == m_metafile[index])
{
index++;//跳过'i'
if (index > m_metafileLen)
{
return ERROR;
}
while ('e' != m_metafile[index])
{
if (index+1 == m_metafileLen)
{
return ERROR;
}else
{
index ++;
}
}//end while
index ++; //跳过'e'
}else if(('0'<=m_metafile[index]) && (m_metafile[index] <= '9'))
{
int len =0;
while (isdigit(m_metafile[index]))
{
len = len*10 + (m_metafile[index]-'0');
index++;
}
index++; //跳过':'
index+=len;
}else if ('e' == m_metafile[index])
{
push_pop --;
if (0 == push_pop)
{
end = index; break;
}
index++;
}else
{
return ERROR;
}
}//end for
//计算hash值
SHA1_CTX context;
SHA1Init(&context);
SHA1Update(&context,&m_metafile[begin], end-begin+1);
SHA1Final(m_metaInfo.info_hash,&context);
cout << endl;
return OK;
}
/*
* 功能:释放类资源
*/
void ResolverMetafile::ReleaseMem()
{
if (NULL != m_metafile)
{
delete[] m_metafile;
m_metafile = NULL;
}
if (NULL != m_metaInfo.pieces)
{
delete[] m_metaInfo.pieces;
}
if (!m_metaInfo.trackerList.empty())
{
for (int i=0; i< int(m_metaInfo.trackerList.size()); i++)
{
delete[] m_metaInfo.trackerList.at(i);
m_metaInfo.trackerList.at(i) = NULL;
}
}
m_metaInfo.trackerList.clear();
if (!m_metaInfo.multiFiles.empty())
{
for (int i=0; i<int(m_metaInfo.multiFiles.size()); i++)
{
if (NULL != (m_metaInfo.multiFiles.at(i).path))
delete[] m_metaInfo.multiFiles.at(i).path;
m_metaInfo.multiFiles.at(i).path = NULL;
}
}
m_metaInfo.multiFiles.clear();
memset(&m_metaInfo, 0, sizeof(m_metaInfo));
}
|
|