using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections; namespace XunleiHelper
{
public class Torrent
{
#region 私有字段
private string _openError = "";
private bool _openFile = false; private string _announce = "";
private IList<string> _announceList = new List<string>();
private DateTime _createTime = new DateTime(, , , , , );
private long _codePage = ;
private string _comment = "";
private string _createdBy = "";
private string _encoding = "";
private string _commentUTF8 = "";
private IList<FileInfo> _fileList = new List<FileInfo>();
private string _name = "";
private string _nameUTF8 = "";
private long _pieceLength = ;
private byte[] _pieces;
private string _publisher = "";
private string _publisherUTF8 = "";
private string _publisherUrl = "";
private string _publisherUrlUTF8 = "";
private IList<string> _notes = new List<string>();
private long _totalLength; #endregion #region 属性
/// <summary>
/// 错误信息
/// </summary>
public string OpenError { set { _openError = value; } get { return _openError; } }
/// <summary>
/// 是否正常打开文件
/// </summary>
public bool OpenFile { set { _openFile = value; } get { return _openFile; } }
/// <summary>
/// 服务器的URL(字符串)
/// </summary>
public string Announce { set { _announce = value; } get { return _announce; } }
/// <summary>
/// 备用tracker服务器列表(列表)
/// </summary>
public IList<string> AnnounceList { set { _announceList = value; } get { return _announceList; } }
/// <summary>
/// 种子创建的时间,Unix标准时间格式,从1970 1月1日 00:00:00到创建时间的秒数(整数)
/// </summary>
public DateTime CreateTime { set { _createTime = value; } get { return _createTime; } }
/// <summary>
/// 未知数字CodePage
/// </summary>
public long CodePage { set { _codePage = value; } get { return _codePage; } }
/// <summary>
/// 种子描述
/// </summary>
public string Comment { set { _comment = value; } get { return _comment; } }
/// <summary>
/// 编码方式
/// </summary>
public string CommentUTF8 { set { _commentUTF8 = value; } get { return _commentUTF8; } }
/// <summary>
/// 创建人
/// </summary>
public string CreatedBy { set { _createdBy = value; } get { return _createdBy; } }
/// <summary>
/// 编码方式
/// </summary>
public string Encoding { set { _encoding = value; } get { return _encoding; } }
/// <summary>
/// 文件信息
/// </summary>
public IList<FileInfo> FileList { set { _fileList = value; } get { return _fileList; } }
/// <summary>
/// 种子名
/// </summary>
public string Name { set { _name = value; } get { return _name; } }
/// <summary>
/// 种子名UTF8
/// </summary>
public string NameUTF8 { set { _nameUTF8 = value; } get { return _nameUTF8; } }
/// <summary>
/// 每个块的大小,单位字节(整数)
/// </summary>
public long PieceLength { set { _pieceLength = value; } get { return _pieceLength; } }
/// <summary>
/// 每个块的20个字节的SHA1 Hash的值(二进制格式)
/// </summary>
private byte[] Pieces { set { _pieces = value; } get { return _pieces; } }
/// <summary>
/// 出版
/// </summary>
public string Publisher { set { _publisher = value; } get { return _publisher; } }
/// <summary>
/// 出版UTF8
/// </summary>
public string PublisherUTF8 { set { _publisherUTF8 = value; } get { return _publisherUTF8; } }
/// <summary>
/// 出版地址
/// </summary>
public string PublisherUrl { set { _publisherUrl = value; } get { return _publisherUrl; } }
/// <summary>
/// 出版地址
/// </summary>
public string PublisherUrlUTF8 { set { _publisherUrlUTF8 = value; } get { return _publisherUrlUTF8; } }
/// <summary>
/// NODES
/// </summary>
public IList<string> Notes { set { _notes = value; } get { return _notes; } } /// <summary>
/// 包含文件的总长度
/// </summary>
public long TotalLength
{
get
{
return _totalLength;
}
} #endregion public Torrent(string fileName)
{
System.IO.FileStream torrentFile = new System.IO.FileStream(fileName, System.IO.FileMode.Open);
byte[] buffer = new byte[torrentFile.Length];
torrentFile.Read(buffer, , buffer.Length);
torrentFile.Close(); if ((char)buffer[] != 'd')
{
if (OpenError.Length == ) OpenError = "错误的Torrent文件,开头第1字节不是100";
return;
}
GetTorrentData(buffer);
} #region 开始读数据 /// <summary>
/// 开始读取
/// </summary>
/// <param name="buffer"></param>
private void GetTorrentData(byte[] buffer)
{
int startIndex = ;
while (true)
{
object Keys = GetKeyText(buffer, ref startIndex);
if (Keys == null)
{
if (startIndex >= buffer.Length) OpenFile = true;
break;
} if (GetValueText(buffer, ref startIndex, Keys.ToString().ToUpper()) == false) break;
}
} #endregion /// <summary>
/// 读取结构
/// </summary>
/// <param name="buffer"></param>
/// <param name="starIndex"></param>
/// <param name="key"></param>
/// <returns></returns>
private bool GetValueText(byte[] buffer, ref int starIndex, string key)
{
switch (key)
{
case "ANNOUNCE":
Announce = GetKeyText(buffer, ref starIndex).ToString();
break;
case "ANNOUNCE-LIST":
int listCount = ;
ArrayList _tempList = GetKeyData(buffer, ref starIndex, ref listCount);
for (int i = ; i != _tempList.Count; i++)
{
AnnounceList.Add(_tempList[i].ToString());
}
break;
case "CREATION DATE":
object date = GetKeyNumb(buffer, ref starIndex).ToString();
if (date == null)
{
if (OpenError.Length == ) OpenError = "CREATION DATE 返回不是数字类型";
return false;
}
CreateTime = CreateTime.AddTicks(long.Parse(date.ToString()));
break;
case "CODEPAGE":
object codePageNumb = GetKeyNumb(buffer, ref starIndex);
if (codePageNumb == null)
{
if (OpenError.Length == ) OpenError = "CODEPAGE 返回不是数字类型";
return false;
}
CodePage = long.Parse(codePageNumb.ToString());
break;
case "ENCODING":
Encoding = GetKeyText(buffer, ref starIndex).ToString();
break;
case "CREATED BY":
CreatedBy = GetKeyText(buffer, ref starIndex).ToString();
break;
case "COMMENT":
Comment = GetKeyText(buffer, ref starIndex).ToString();
break;
case "COMMENT.UTF-8":
CommentUTF8 = GetKeyText(buffer, ref starIndex).ToString();
break;
case "INFO":
int fileListCount = ;
GetFileInfo(buffer, ref starIndex, ref fileListCount);
break;
case "NAME":
Name = GetKeyText(buffer, ref starIndex).ToString();
break;
case "NAME.UTF-8":
NameUTF8 = GetKeyText(buffer, ref starIndex).ToString();
break;
case "PIECE LENGTH":
object pieceLengthNumb = GetKeyNumb(buffer, ref starIndex);
if (pieceLengthNumb == null)
{
if (OpenError.Length == ) OpenError = "PIECE LENGTH 返回不是数字类型";
return false;
}
PieceLength = long.Parse(pieceLengthNumb.ToString());
break;
case "PIECES":
Pieces = GetKeyByte(buffer, ref starIndex);
break;
case "PUBLISHER":
Publisher = GetKeyText(buffer, ref starIndex).ToString();
break;
case "PUBLISHER.UTF-8":
PublisherUTF8 = GetKeyText(buffer, ref starIndex).ToString();
break;
case "PUBLISHER-URL":
PublisherUrl = GetKeyText(buffer, ref starIndex).ToString();
break;
case "PUBLISHER-URL.UTF-8":
PublisherUrlUTF8 = GetKeyText(buffer, ref starIndex).ToString();
break;
case "NODES":
int nodesCount = ;
ArrayList _nodesList = GetKeyData(buffer, ref starIndex, ref nodesCount);
int ipCount = _nodesList.Count / ;
for (int i = ; i != ipCount; i++)
{
Notes.Add(_nodesList[i * ] + ":" + _nodesList[(i * ) + ]);
}
break; default:
return false;
}
return true;
} #region 获取数据
/// <summary>
/// 获取列表方式 "I1:Xe"="X" 会调用GetKeyText
/// </summary>
/// <param name="buffer"></param>
/// <param name="starIndex"></param>
/// <param name="listCount"></param>
private ArrayList GetKeyData(byte[] buffer, ref int starIndex, ref int listCount)
{
ArrayList _tempList = new ArrayList();
while (true)
{
string textStar = System.Text.Encoding.UTF8.GetString(buffer, starIndex, );
switch (textStar)
{
case "l":
starIndex++;
listCount++;
break;
case "e":
listCount--;
starIndex++;
if (listCount == ) return _tempList;
break;
case "i":
_tempList.Add(GetKeyNumb(buffer, ref starIndex).ToString());
break;
default:
object listText = GetKeyText(buffer, ref starIndex);
if (listText != null)
{
_tempList.Add(listText.ToString());
}
else
{
if (OpenError.Length == )
{
OpenError = "错误的Torrent文件,ANNOUNCE-LIST错误";
return _tempList;
}
}
break;
}
}
}
/// <summary>
/// 获取字符串
/// </summary>
/// <param name="buffer"></param>
/// <param name="startIndex"></param>
/// <returns></returns>
private object GetKeyText(byte[] buffer, ref int startIndex)
{
int numb = ;
int leftNumb = ;
for (int i = startIndex; i != buffer.Length; i++)
{
if ((char)buffer[i] == ':') break;
if ((char)buffer[i] == 'e')
{
leftNumb++;
continue;
}
numb++;
} startIndex += leftNumb;
string textNumb = System.Text.Encoding.UTF8.GetString(buffer, startIndex, numb);
try
{
int readNumb = Int32.Parse(textNumb);
startIndex = startIndex + numb + ;
object keyText = System.Text.Encoding.UTF8.GetString(buffer, startIndex, readNumb);
startIndex += readNumb;
return keyText;
}
catch
{
return null;
} } /// <summary>
/// 获取数字
/// </summary>
/// <param name="buffer"></param>
/// <param name="startIndex"></param>
private object GetKeyNumb(byte[] buffer, ref int startIndex)
{
if (System.Text.Encoding.UTF8.GetString(buffer, startIndex, ) == "i")
{
int numb = ;
for (int i = startIndex; i != buffer.Length; i++)
{
if ((char)buffer[i] == 'e') break;
numb++;
}
startIndex++;
long retNumb = ;
try
{
retNumb = long.Parse(System.Text.Encoding.UTF8.GetString(buffer, startIndex, numb - ));
startIndex += numb;
return retNumb;
}
catch
{
return null;
}
}
else
{
return null;
} } /// <summary>
/// 获取BYTE数据
/// </summary>
/// <param name="buffer"></param>
/// <param name="startIndex"></param>
/// <returns></returns>
private byte[] GetKeyByte(byte[] buffer, ref int startIndex)
{
int numb = ;
for (int i = startIndex; i != buffer.Length; i++)
{
if ((char)buffer[i] == ':') break;
numb++;
}
string textNumb = System.Text.Encoding.UTF8.GetString(buffer, startIndex, numb); try
{
int readNumb = Int32.Parse(textNumb);
startIndex = startIndex + numb + ;
System.IO.MemoryStream keyMemory = new System.IO.MemoryStream(buffer, startIndex, readNumb);
byte[] keyBytes = new byte[readNumb];
keyMemory.Read(keyBytes, , readNumb);
keyMemory.Close();
startIndex += readNumb;
return keyBytes;
}
catch
{
return null;
}
} /// <summary>
/// 对付INFO的结构
/// </summary>
/// <param name="buffer"></param>
/// <param name="startIndex"></param>
/// <param name="listCount"></param>
private void GetFileInfo(byte[] buffer, ref int startIndex, ref int listCount)
{
if ((char)buffer[startIndex] != 'd') return;
startIndex++; if (GetKeyText(buffer, ref startIndex).ToString().ToUpper() == "FILES")
{
FileInfo info = new FileInfo(); while (true)
{
string TextStar = System.Text.Encoding.UTF8.GetString(buffer, startIndex, ); switch (TextStar)
{
case "l":
startIndex++;
listCount++;
break;
case "e":
listCount--;
startIndex++;
if (listCount == ) FileList.Add(info);
if (listCount == ) return;
break;
case "d":
info = new FileInfo();
listCount++;
startIndex++;
break; default:
object listText = GetKeyText(buffer, ref startIndex);
if (listText == null) return;
switch (listText.ToString().ToUpper()) //转换为大写
{
case "ED2K":
info.De2K = GetKeyText(buffer, ref startIndex).ToString();
break;
case "FILEHASH":
info.FileHash = GetKeyText(buffer, ref startIndex).ToString();
break; case "LENGTH":
info.Length = Convert.ToInt64(GetKeyNumb(buffer, ref startIndex));
_totalLength += info.Length;
break;
case "PATH":
int PathCount = ;
ArrayList PathList = GetKeyData(buffer, ref startIndex, ref PathCount);
string Temp = "";
for (int i = ; i != PathList.Count; i++)
{
if (i < PathList.Count && i != )
Temp += "\\";
Temp += PathList[i].ToString();
}
info.Path = Temp;
break;
case "PATH.UTF-8":
int pathUtf8Count = ;
ArrayList pathutf8List = GetKeyData(buffer, ref startIndex, ref pathUtf8Count);
string utfTemp = "";
for (int i = ; i != pathutf8List.Count; i++)
{
utfTemp += pathutf8List[i].ToString();
}
info.PathUTF8 = utfTemp;
break;
}
break;
} } }
} #endregion /// <summary>
/// 对应结构 INFO 多个文件时
/// </summary>
public class FileInfo
{
private string path = "";
private string pathutf8 = "";
private long length = ;
private string md5sum = "";
private string de2k = "";
private string filehash = ""; /// <summary>
/// 文件路径
/// </summary>
public string Path { get { return path; } set { path = value; } }
/// <summary>
/// UTF8的名称
/// </summary>
public string PathUTF8 { get { return pathutf8; } set { pathutf8 = value; } }
/// <summary>
/// 文件大小
/// </summary>
public long Length { get { return length; } set { length = value; } }
/// <summary>
/// MD5验效 (可选)
/// </summary>
public string MD5Sum { get { return md5sum; } set { md5sum = value; } }
/// <summary>
/// ED2K 未知
/// </summary>
public string De2K { get { return de2k; } set { de2k = value; } }
/// <summary>
/// FileHash 未知
/// </summary>
public string FileHash { get { return filehash; } set { filehash = value; } }
}
}
}
扩展阅读:b编码级种子文件的解析
En解释+API:http://wiki.theory.org/BitTorrentSpecification (推荐LordMike所写的库:下载)
原文:http://hi.baidu.com/kongfl888/item/6c97d4cb14a35b42a8ba94f8