Torrent文件

冉德元
2023-12-01

 BitTorrent下载时,用户必须下载一个.torrent文件,它就是所谓"Metainfo file",里面存储有关于下载内容的announce地址,长度,大小,SHA1杂凑项等内容。它由Bencode编码组成.而且字符串是用UTF-8编码的。不过在中国,常常使用GBK编码。它由如下几项组成:
 Info:描述下载内容的信息,是一个字典.有两种可能,一种是"单文件"模式:当BitTorrent只下载一个文件的时候使用.另一种是"多文件"模式,是在下载多个内容的时候使用.两种情况下Info各有不同.
          单文件模式:
 length:整数,指文件的大小.
 md5sum:(可选),字符串,含有32字节md5校验码.BitTorrent没有使用MD5而是使用了SHA1作为自已的签名算法.这是为其他P2P软件兼容而设置的可选内容.
 name:字符串,这是下载文件的名字,纯粹是建议.
 piece length:整数,是BitTorrent文件块的大小.
 pieces:字符串,连续的存放着所有块的SHA1杂凑值,每一个文件块的杂凑值为20字节.
          多文件模式:
 files: 一个由字典组成的列表,每个字典表示一个文件,字典的键值有如下内容:
 length:整数,指当前文件的大小.
 md5sum:(可选),字符串,同单文件模式,指当前文件.
 path:由字符串组成的列表,每个列表元素指一个路径名中的一个目录或文件名.比如说:"l3:abc3:abc:6abc.txte",指文件路径"abc/abc/abc.txt".
 name:字符串,BitTorrent下载路径中最上层的目录名
 piece length:整数,是BitTorrent文件块的大小.
 pieces:字符串,连续的存放着所有块的SHA1杂凑值,每一个文件块的杂凑值为20字节.
 announce:字符串,指向tracker的URL.
 announce-list:(可选),字典,这是一个对官方协议的扩展,支持"多Tracker".
 creation date:(可选),整数,创建日期(UNIX创世纪格式:1970-1-1日00:00UTC到当时的秒数)
 comment:(可选),字符串,注释
 created by:可选,字符串,创建此.torrent文件的BT下载端程序名和版本号
 encoding:BitComet对Metafile的扩展,一般用来指出不使用utf-8而使用gbk.

 
 具体文件结构如下:
 全部内容必须都为bencoding编码类型。
 整个文件为一个字典结构,包含如下关键字
 announce:tracker服务器的URL(字符串)
 announce-list(可选):备用tracker服务器列表(列表)
 creation date(可选):种子创建的时间,Unix标准时间格式,从1970 1月1日 00:00:00到创建时间的秒数(整数)
 comment(可选):备注(字符串)
 created by(可选):创建人或创建程序的信息(字符串)
 
 info:一个字典结构,包含文件的主要信息,为分二种情况:单文件结构或多文件结构
 单文件结构如下:
       length:文件长度,单位字节(整数)
       md5sum(可选):长32个字符的文件的MD5校验和,BT不使用这个值,只是为了兼容一些程序所保留!(字符串)
       name:文件名(字符串)
       piece length:每个块的大小,单位字节(整数)
       pieces:每个块的20个字节的SHA1 Hash的值(二进制格式)
 多文件结构如下:
       files:一个字典结构
           length:文件长度,单位字节(整数)
           md5sum(可选):同单文件结构中相同
          path:文件的路径和名字,是一个列表结构,如/test/test.txt 列表为l4:test8test.txte 

程序如下:

class CBTCode
{
public:
 CBTCode();
 ~CBTCode();
public:
 BOOL   BTEnCode(const BYTE* pData, int nLeftLen);
 BOOL   BTDeCode(BYTE* pData, int nLeftLen);
 BTItemType  GetType();
 void   SetType(BTItemType ItemType);
 CBTBaseItem* GetValue();
 void   SetValue(CBTBaseItem*  pBaseItem);
 int    GetBufSize();
private:
 BOOL         BTEnCode(const BYTE* pData, int nLeftLen, int& nLen);
 BOOL         BTDeCode(BYTE* pData, int nLeftLen, int& nLen);
private:
 BTItemType    m_ItemType;
 union
 {
  CBTIntItem*   m_pBTInt;
  CBTStrItem*   m_pBTStr;
  CBTListItem*  m_pBTList;
  CBTDicItem*   m_pBTDic;
 };

};

CBTCode::CBTCode()
{
 m_ItemType = BT_ITEM_UNKNOWN;
}

CBTCode::~CBTCode()
{
 switch(m_ItemType)
 {
 case BT_ITEM_INT:
  m_pBTInt->Release();
  break;
 case BT_ITEM_STR:
  m_pBTStr->Release();
  break;
 case BT_ITEM_LIST:
  m_pBTList->Release();
  break;
 case BT_ITEM_DIC:
  m_pBTDic->Release();
  break;
 default:
  break;
 }
}

void CBTCode::SetType(BTItemType ItemType)
{
 m_ItemType = ItemType;
}

BTItemType CBTCode::GetType()
{
 return m_ItemType;
}

void CBTCode::SetValue(CBTBaseItem* pBaseItem)
{
 switch(m_ItemType)
 {
 case BT_ITEM_INT:
  m_pBTInt = (CBTIntItem*)pBaseItem;
  m_pBTInt->AddRef();
  break;
 case BT_ITEM_STR:
  m_pBTStr = (CBTStrItem*)pBaseItem;
  m_pBTStr->AddRef();
  break;
 case BT_ITEM_LIST:
  m_pBTList = (CBTListItem*)pBaseItem;
  m_pBTList->AddRef();
  break;
 case BT_ITEM_DIC:
  m_pBTDic = (CBTDicItem*)pBaseItem;
  m_pBTDic->AddRef();
 default:
  break;
 }
}

CBTBaseItem* CBTCode::GetValue()
{
 switch(m_ItemType)
 {
 case BT_ITEM_INT:
  return m_pBTInt;
 case BT_ITEM_STR:
  return m_pBTStr;
 case BT_ITEM_LIST:
  return m_pBTList;
 case BT_ITEM_DIC:
  return m_pBTDic;
 default:
  return NULL;
 }
}

int CBTCode::GetBufSize()
{
 switch(m_ItemType)
 {
 case BT_ITEM_INT:
  return m_pBTInt->GetBufSize();
 case BT_ITEM_STR:
  return m_pBTStr->GetBufSize();
 case BT_ITEM_LIST:
  return m_pBTList->GetBufSize();
 case BT_ITEM_DIC:
  return m_pBTDic->GetBufSize();
 default:
  return 0;
 }
}

//传内存的大小
BOOL CBTCode::BTEnCode(const BYTE* pData, int nLeftLen)
{
 if (NULL == pData || *pData == 0 || nLeftLen <= 1)
  return FALSE;
 int nLen = 0;
 const BYTE* pTemp = pData;
 BOOL bRes = BTEnCode(pTemp, nLeftLen, nLen);
 if (bRes && nLeftLen == nLen)
  return TRUE;
 return FALSE;
}

BOOL CBTCode::BTEnCode(const BYTE* pData, int nLeftLen, int& nLen)
{
 const BYTE* pTemp = pData;
 switch(*pTemp++)
 {
 case 'i':
  {
   char nVal[50] = {0};
   int i = 0;
   while(*pTemp >= '0' && *pTemp <= '9')
   {
    nVal[i++] = *pTemp++;
   }
   if (*pTemp == 'e')
   {
    m_ItemType = BT_ITEM_INT;
    m_pBTInt = new CBTIntItem;
    m_pBTInt->SetValue(_atoi64(nVal));
    nLen = pTemp - pData + 1;     //加1的原因是*pTemp = 'e'
    return TRUE;
   }
   else
   {
    return FALSE;
   }
  }
 case '0':
 case '1':
 case '2':
 case '3':
 case '4':
 case '5':
 case '6':
 case '7':
 case '8':
 case '9':
  {
   pTemp--;
   char nVal[50] = {0};
   int i = 0;
   while(*pTemp >= '0' && *pTemp <= '9')
   {
    nVal[i++] = *pTemp++;
   }
   int nStrLen = atoi(nVal);
   
   if (*pTemp == ':')
   {
    pTemp++;
    m_ItemType = BT_ITEM_STR;
    m_pBTStr = new CBTStrItem;    
    m_pBTStr->SetValue(string((char*)pTemp, nStrLen));
    pTemp = pTemp + nStrLen;
    nLen = pTemp - pData;      //字符串不是以e结束
    return TRUE;
   }
   else
   {
    return FALSE;
   }
  }
 case 'l':
  {
   m_ItemType = BT_ITEM_LIST;
   m_pBTList = new CBTListItem;
   int nTempLen = 0;
   int nTempLeft = nLeftLen - 1;
   while(*pTemp != 0 && *pTemp != 'e')
   {
    CBTCode btCode;    
    if (!btCode.BTEnCode(pTemp, nTempLeft, nTempLen))   
     return FALSE;
    nTempLeft = nTempLeft - nTempLen;
    pTemp = pTemp + nTempLen;    
    CBTBaseItem* pValue = btCode.GetValue();
    m_pBTList->AddValue(pValue);
   }
   if (*pTemp == 'e')
   {
    nLen = pTemp - pData + 1;
    return TRUE;
   }
   else
   {
    return FALSE;
   }
  }
 case 'd':
  {
   m_ItemType = BT_ITEM_DIC;
   m_pBTDic = new CBTDicItem;
   int nTempLen =0;
   int nTempLeft = nLeftLen - 1;
   while(*pTemp != 0 && *pTemp != 'e')
   {
    CBTCode key;
    if (!key.BTEnCode(pTemp, nTempLeft, nTempLen) || key.GetType() != BT_ITEM_STR)
     return FALSE;
    nTempLeft = nTempLeft - nTempLen;
    pTemp = pTemp + nTempLen;
    CBTCode value;
    if (!value.BTEnCode(pTemp, nTempLeft, nTempLen))
     return FALSE;
    nTempLeft = nTempLeft - nTempLen;
    pTemp = pTemp + nTempLen;
    
    CBTStrItem* pKey = (CBTStrItem*)key.GetValue();
    CBTBaseItem* pValue = value.GetValue();
    m_pBTDic->AddValue(pKey->GetValue(), pValue);
   }
   if (*pTemp == 'e')
   {
    nLen = pTemp - pData + 1;
    return TRUE;
   }
   else
   {
    return FALSE;
   }
  }
  
 }
 return FALSE;
}

//将数据结构内的值写到pData上
BOOL CBTCode::BTDeCode(BYTE* pData, int nLeftLen)
{
 BYTE* pTemp = pData;
 int nLen = 0;
 return BTDeCode(pTemp, nLeftLen, nLen);
}

BOOL CBTCode::BTDeCode(BYTE* pData, int nLeftLen, int& nLen)
{
 if (nLeftLen == 0)
  return TRUE;
 BYTE* pTemp = pData;
 switch(m_ItemType)
 {
 case BT_ITEM_INT:
  {
   sprintf((char*)pTemp, "i%I64d", m_pBTInt->GetValue());
   pTemp += strlen((char*)pTemp);
   *pTemp++ = 'e';
   nLen = pTemp - pData;
   if (m_pBTInt->GetBufSize() != nLen)
    return FALSE;
   return TRUE;
  }
 case BT_ITEM_STR:
  {
   int strLen = m_pBTStr->GetValue().size();
   sprintf((char*)pTemp, "%d:", strLen);
   pTemp += Int2String(strLen).size() + 1;
   memcpy(pTemp, m_pBTStr->GetValue().c_str(), strLen);
   pTemp += strLen;
   nLen = pTemp - pData;
   if (m_pBTStr->GetBufSize() != nLen)
    return FALSE;
   return TRUE;
  }
 case BT_ITEM_LIST:
  {
   *pTemp++ = 'l';
   nLeftLen--;
   int AllLen = 0;
   int nTempLen = 0;
   for (int index = 0; index < m_pBTList->GetSize(); ++index)
   { 
    nTempLen = 0;
    CBTBaseItem* pBase = m_pBTList->GetValue(index);
    CBTCode btCode;
    btCode.SetType(pBase->GetItemType());
    btCode.SetValue(pBase);
    if (!btCode.BTDeCode(pTemp, nLeftLen - nTempLen, nTempLen))
     return FALSE;
    pTemp += nTempLen;
    AllLen += nTempLen;
   }
   *pTemp++ = 'e';
   nLeftLen--;
   nLen = pTemp - pData;
   if (m_pBTList->GetBufSize() != AllLen + 2)
    return FALSE;
   return TRUE;
  }
 case BT_ITEM_DIC:
  {
   *pTemp++ = 'd';
   nLeftLen--;
   int nTempLen = 0;
   int nTempLeft = 0;
   for (Map::iterator pos = m_pBTDic->m_MapValue.begin(); pos != m_pBTDic->m_MapValue.end(); ++pos)
   {
    nTempLeft = 0;
    nTempLen = 0;
    string strKey(pos->first);
    int strLen = strKey.size();
    sprintf((char*)pTemp, "%d:", strLen);
    nTempLeft += Int2String(strLen).size() + 1;
    pTemp += nTempLeft;
    memcpy(pTemp, strKey.c_str(), strLen);
    pTemp += strLen;     //字符串个数
    nTempLeft += strLen;
    
    CBTBaseItem * pBase = pos->second;
    CBTCode btCode;
    btCode.SetType(pBase->GetItemType());
    btCode.SetValue(pBase);
    if (!btCode.BTDeCode(pTemp, nLeftLen - nTempLeft, nTempLen))
     return FALSE;
    pTemp += nTempLen;
   }
   *pTemp++ = 'e';
   nLeftLen--;
   nLen = pTemp - pData;
   if (m_pBTDic->GetBufSize() != nLen)
    return FALSE;
   return TRUE;
  }
 default:
  break;
 }
 return FALSE;
}

 

 

 类似资料: