基本信息
源码名称:bt种子文件解析 含源码下载
源码大小:0.15M
文件格式:.zip
开发语言:Python
更新时间:2013-10-21
友情提示:(无需注册或充值,赞助后即可获取资源下载链接)
嘿,亲!知识可是无价之宝呢,但咱这精心整理的资料也耗费了不少心血呀。小小地破费一下,绝对物超所值哦!如有下载和支付问题,请联系我们QQ(微信同号):813200300
本次赞助数额为: 2 元×
微信扫码支付:2 元
×
请留下您的邮箱,我们将在2小时内将文件发到您的邮箱
源码介绍
{BTTorrent B编码(Bencoding)格式分析}
unit DxBencoding;
interface
uses Classes,SysUtils,Generics.Collections;
type
(*
Torrent文件格式
Multi-file Torrent 多文件
├─announce
├─announce-list
├─comment
├─comment.utf-8
├─creation date
├─encoding
├─info
│ ├─files
│ │ ├─length
│ │ ├─path
│ │ └─path.utf-8
│ ├─name
│ ├─name.utf-8
│ ├─piece length
│ ├─pieces
│ ├─publisher
│ ├─publisher-url
│ ├─publisher-url.utf-8
│ └─publisher.utf-8
└─nodes
Single-File Torrent 单文件
├─announce
├─announce-list
├─comment
├─comment.utf-8
├─creation date
├─encoding
├─info
│ ├─length
│ ├─name
│ ├─name.utf-8
│ ├─piece length
│ ├─pieces
│ ├─publisher
│ ├─publisher-url
│ ├─publisher-url.utf-8
│ └─publisher.utf-8
└─nodes
*)
//B编码支持的数据类型
TDxBenValueTypes = (DBV_String,DBV_Int,DBV_List,DBV_Dictionary);
//B编码的节点,类似于JSON节点,
TDxBenValue = class
private
FParent: TDxBenValue;
protected
function GetType:TDxBenValueTypes; virtual; abstract;
procedure Parser(str: string);virtual;abstract;
function GetAsInteger: Integer;virtual;abstract;
function GetAsString: string;virtual;abstract;
function GetObject: TDxBenValue;virtual;
public
constructor Create;overload;virtual;
constructor Create(str: string);overload;virtual;
property ValueType: TDxBenValueTypes read GetType;
function ToString: string;override;
property Parent: TDxBenValue read FParent;
property AsInteger: Integer read GetAsInteger;
property AsString: string read GetAsString;
property AsValueObject: TDxBenValue read GetObject;
end;
TDxBenInt = class(TDxBenValue)
private
FValue: Integer;
protected
function GetType:TDxBenValueTypes;override;
function GetAsInteger: Integer;override;
procedure Parser(str: string);override;
function GetAsString: string;override;
function GetObject: TDxBenValue;override;
public
constructor Create;override;
function ToString: string;override;
end;
TDxBenString = class(TDxBenValue)
private
FValue: string;
protected
function GetType:TDxBenValueTypes;override;
function GetAsString: string;override;
function GetObject: TDxBenValue;override;
function GetAsInteger: Integer;override;
procedure Parser(str: string);override;
public
function ToString: string;override;
end;
TDxBenDictionary = class;
TDxBenList = class(TDxBenValue)
private
FList: TList;
function GetCount: Integer;
function GetValues(index: Integer): TDxBenValue;
protected
procedure Parser(str: string);override;
procedure ParserToList(var P: Pchar;List: TDxBenList);
procedure ParserToDictionary(var p: PChar;Dict: TDxBenDictionary);
function GetType:TDxBenValueTypes;override;
function GetAsString: string;override;
function GetObject: TDxBenValue;override;
function GetAsInteger: Integer;override;
public
procedure Clear;
constructor Create; override;
constructor CreateFromString(str: string);
destructor Destroy;override;
function ToString: string;override;
property Count: Integer read GetCount;
property Values[index: Integer]: TDxBenValue read GetValues;
end;
TDxBenDictionary = class(TDxBenValue)
private
FDict: TDictionary<string,TDxBenValue>;
function GetCount: Integer;
function GetValues(Key: string): TDxBenValue;
protected
procedure ParserToList(var P: Pchar;List: TDxBenList);
procedure ParserToDictionary(var p: PChar;Dict: TDxBenDictionary);
procedure Parser(str: string);override;
function GetType:TDxBenValueTypes;override;
function GetAsString: string;override;
function GetObject: TDxBenValue;override;
function GetAsInteger: Integer;override;
public
procedure Clear;
constructor Create;override;
destructor Destroy;override;
function ToString: string;override;
property Count: Integer read GetCount;
property Values[Key: string]: TDxBenValue read GetValues;
end;
TDxBtInfo = class(TDxBenDictionary)
private
function GetSingleFile: Boolean;
function GetFiles: TDxBenList;
function GetName: string;
function GetNameUtf8: string;
function Getpublisher: string;
function GetpublisherUtf8: string;
function Getpublisherurl: string;
function GetpublisherurlUtf8: string;
public
property SingleFile: Boolean read GetSingleFile;
property Files: TDxBenList read GetFiles;
property Name: string read GetName;
property NameUtf8: string read GetNameUtf8;
property publisher: string read Getpublisher;
property publisherUtf8: string read GetpublisherUtf8;
property publisherurl: string read Getpublisherurl;
property publisherurlUtf8: string read GetpublisherurlUtf8;
end;
TDxTorrentFile = class
private
FDict: TDxBenDictionary;
procedure ParserStream(Stream: TStream;Dict: TDxBenDictionary);overload;
procedure ParserStreamToList(Stream: TStream; List: TDxBenList);
function GetComment: string;
function GetEncoding: string;
function GetCreator: string;
function Getannounce: string;
function Getannounce_list: TDxBenList;
function GetBtInfo: TDxBtInfo;
function GetCreateDate: TDateTime;
public
procedure Clear;
constructor Create;
destructor Destroy;override;
procedure LoadFromFile(FileName: string);
procedure LoadFromStream(Stream: TStream);
property Comment: string read GetComment;
property Encoding: string read GetEncoding;
property Creator: string read GetCreator;
property announce: string read Getannounce;
property announce_list: TDxBenList read Getannounce_list;
property BtInfo: TDxBtInfo read GetBtInfo;
property CreateDate: TDateTime read GetCreateDate;
end;
implementation
{ TDxBenValue }
constructor TDxBenValue.Create;
begin
FParent := nil;
end;
constructor TDxBenValue.Create(str: string);
begin
Create;
Parser(str);
end;
function TDxBenValue.GetObject: TDxBenValue;
begin
Result := Self;
end;
function TDxBenValue.ToString: string;
begin
Result := '';
end;
{ TDxBenInt }
constructor TDxBenInt.Create;
begin
inherited;
FValue := 0;
end;
function TDxBenInt.GetAsInteger: Integer;
begin
Result := FValue;
end;
function TDxBenInt.GetAsString: string;
begin
Result := IntToStr(FValue);
end;
function TDxBenInt.GetObject: TDxBenValue;
begin
Result := Self;
end;
function TDxBenInt.GetType: TDxBenValueTypes;
begin
Result := DBV_Int;
end;
procedure TDxBenInt.Parser(str: string);
var
len: Integer;
begin
len := Length(str);
if (UpperCase(str[1]) = 'I') and (UpperCase(str[len]) = 'E') then
begin
Str := Copy(str,2,len - 2);
if not TryStrToInt(str,FValue) then
raise Exception.Create('无效的B编码整数格式');
end
else raise Exception.Create('无效的B编码整数格式');
end;
function TDxBenInt.ToString: string;
begin
Result := 'i' inttostr(FValue) 'e';
end;
{ TDxBenString }
function TDxBenString.GetAsInteger: Integer;
begin
raise Exception.Create('字符串类型数据');
end;
function TDxBenString.GetAsString: string;
begin
Result := FValue;
end;
function TDxBenString.GetObject: TDxBenValue;
begin
Result := Self;
end;
function TDxBenString.GetType: TDxBenValueTypes;
begin
Result := DBV_String;
end;
procedure TDxBenString.Parser(str: string);
var
ipos: Integer;
str1: string;
begin
FValue := '';
ipos := Pos(':',str);
if ipos <= 1 then
raise Exception.Create('无效的数据格式')
else
begin
str1 := Copy(str,1,ipos - 1);
if not TryStrToInt(str1,ipos) then
raise Exception.Create('无效的数据格式');
FValue := Copy(str,ipos 1,ipos);
end;
end;
function TDxBenString.ToString: string;
var
len: Integer;
begin
len := Length(FValue);
if len > 0 then
Result := IntToStr(len) ':' FValue
else Result := '';
end;
{ TDxBenList }
procedure TDxBenList.Clear;
begin
while FList.Count > 0 do
begin
TDxBenValue(FList[FList.Count - 1]).Free;
FList.Delete(FList.Count - 1);
end;
end;
constructor TDxBenList.Create;
begin
inherited;
FList := TList.Create;
end;
constructor TDxBenList.CreateFromString(str: string);
begin
Create;
Parser(str);
end;
destructor TDxBenList.Destroy;
begin
Clear;
FList.Free;
inherited;
end;
function TDxBenList.GetAsInteger: Integer;
begin
raise Exception.Create('列表不支持');
end;
function TDxBenList.GetAsString: string;
begin
raise Exception.Create('列表不支持');
end;
function TDxBenList.GetCount: Integer;
begin
Result := FList.Count;
end;
function TDxBenList.GetObject: TDxBenValue;
begin
Result := inherited;
end;
function TDxBenList.GetType: TDxBenValueTypes;
begin
Result := DBV_List;
end;
function TDxBenList.GetValues(index: Integer): TDxBenValue;
begin
if index in [0..FList.Count-1] then
Result := FList[index]
else Result := nil;
end;
procedure TDxBenList.Parser(str: string);
var
len: Integer;
p: PChar;
begin
len := Length(str);
Clear;
if (UpperCase(str[1]) = 'L') and (UpperCase(str[len]) = 'E') then
begin
Str := Copy(str,2,len - 2);
p := @str[1];
ParserToList(p,nil);
end
else raise Exception.Create('无效的B编码列表格式');
end;
procedure TDxBenList.ParserToDictionary(var p: PChar; Dict: TDxBenDictionary);
type
TParserState = (PS_None,PS_Key,PS_Value);
var
t: Char;
st: string;
FInt: Integer;
IntValue: TDxBenInt;
ListValue: TDxBenList;
StrValue: TDxBenString;
DicValue: TDxBenDictionary;
Parstate: TParserState;
key: string;
begin
//开始解析
Parstate := PS_None;
while p^ <> '' do
begin
t := P^;
case t of
'i':
begin
//整数
if Parstate <> PS_Value then
raise Exception.Create('B编码字典的Key必须是字符串!');
Inc(p);
st := '';
while p^ <> 'e' do
begin
if not CharInSet(p^, ['-','0'..'9']) then
raise Exception.Create('无效的数据类型');
st := st p^;
Inc(p);
end;
if not TryStrToInt(st,FInt) then
raise Exception.Create('无效的数据类型i' st 'e');
IntValue := TDxBenInt.Create;
IntValue.FValue := FInt;
IntValue.FParent := Dict;
Dict.FDict[Key] := IntValue;
Inc(p);
end;
'l':
begin
if Parstate <> PS_Value then
raise Exception.Create('B编码字典的Key必须是字符串!');
Inc(p);
ListValue := TDxBenList.Create;
ListValue.FParent := Dict;
Dict.FDict[Key] := ListValue;
ParserToList(p,ListValue);
end;
'd':
begin
if Parstate <> PS_Value then
raise Exception.Create('B编码字典的Key必须是字符串!');
Inc(p);
DicValue := TDxBenDictionary.Create;
DicValue.FParent := Dict;
Dict.FDict[Key] := DicValue;
ParserToDictionary(p,DicValue);
end;
'e':
begin
if Parstate = PS_Value then
Parstate := PS_None
else if Parstate = PS_None then
Break;
end;
else
begin
st := '';
while p^ <> ':' do
begin
if not CharInSet(p^, ['-','0'..'9']) then
raise Exception.Create('无效的数据类型');
st := st p^;
Inc(p);
end;
if not TryStrToInt(st,FInt) then
raise Exception.Create('无效的数据类型' st);
//读取字符串
Inc(p);
if StrLen(p) < FInt then
raise Exception.Create('字符串解析长度不够');
SetLength(st,Fint);
Move(p^,Pointer(St)^,FInt*Sizeof(Char));
Inc(p,Fint);
if Parstate = PS_None then
begin
key := st;
if Dict.FDict.ContainsKey(st) then
raise Exception.Create('字典存在重复信息');
Dict.FDict.Add(st,nil);
Parstate := PS_Value;
end
else if Parstate = PS_Value then
begin
StrValue := TDxBenString.Create;
StrValue.FParent := Dict;
StrValue.FValue := st;
Dict.FDict[Key] := StrValue;
end;
end;
end;
end;
end;
procedure TDxBenList.ParserToList(var P: PChar; List: TDxBenList);
var
t: Char;
st: string;
FInt: Integer;
IntValue: TDxBenInt;
ListValue: TDxBenList;
StrValue: TDxBenString;
DicValue: TDxBenDictionary;
begin
//开始解析
while p^ <> '' do
begin
t := P^;
case t of
'i':
begin
//是一个整数
Inc(p);
st := '';
while p^ <> 'e' do
begin
if not CharInSet(p^, ['-','0'..'9']) then
raise Exception.Create('无效的数据类型');
st := st p^;
Inc(p);
end;
if not TryStrToInt(st,FInt) then
raise Exception.Create('无效的数据类型i' st 'e');
IntValue := TDxBenInt.Create;
IntValue.FValue := FInt;
if List = nil then
begin
IntValue.FParent := Self;
FList.Add(IntValue);
end
else
begin
IntValue.FParent := List;
List.FList.Add(IntValue)
end;
Inc(p);
end;
'l':
begin
//列表
Inc(p);
ListValue := TDxBenList.Create;
if List = nil then
begin
ListValue.FParent := Self;
FList.Add(ListValue);
end
else
begin
ListValue.FParent := List;
List.FList.Add(ListValue)
end;
ParserToList(p,ListValue);
end;
'd':
begin
//字典
Inc(p);
DicValue := TDxBenDictionary.Create;
if List = nil then
begin
DicValue.FParent := Self;
FList.Add(DicValue);
end
else
begin
DicValue.FParent := List;
List.FList.Add(DicValue)
end;
ParserToDictionary(p,DicValue);
end;
'e': Break;//结束了
else
begin
//字符串
st := '';
while p^ <> ':' do
begin
if not CharInSet(p^, ['-','0'..'9']) then
raise Exception.Create('无效的数据类型');
st := st p^;
Inc(p);
end;
if not TryStrToInt(st,FInt) then
raise Exception.Create('无效的数据类型' st);
//读取字符串
Inc(p);
if StrLen(p) < FInt then
raise Exception.Create('字符串解析长度不够');
StrValue := TDxBenString.Create;
SetLength(StrValue.FValue,Fint);
Move(p^,Pointer(StrValue.FValue)^,FInt*Sizeof(Char));
if List = nil then
begin
StrValue.FParent := Self;
FList.Add(StrValue);
end
else
begin
StrValue.FParent := List;
List.FList.Add(StrValue)
end;
Inc(p,Fint);
end;
end;
end;
end;
function TDxBenList.ToString: string;
var
i: Integer;
V: TDxBenValue;
begin
for i := 0 to FList.Count - 1 do
begin
V := FList[i];
Result := Result V.ToString;
end;
end;
{ TDxBenDictionary }
procedure TDxBenDictionary.Clear;
var
Pair: TPair<string,TDxBenValue>;
begin
for Pair in FDict do
begin
Pair.Value.Free;
end;
FDict.Clear;
end;
constructor TDxBenDictionary.Create;
begin
FDict := TDictionary<string,TDxBenValue>.Create;
end;
destructor TDxBenDictionary.Destroy;
begin
Clear;
FDict.Free;
inherited;
end;
function TDxBenDictionary.GetAsInteger: Integer;
begin
raise Exception.Create('字典不支持');
end;
function TDxBenDictionary.GetAsString: string;
begin
raise Exception.Create('字典不支持');
end;
function TDxBenDictionary.GetCount: Integer;
begin
Result := FDict.Count;
end;
function TDxBenDictionary.GetObject: TDxBenValue;
begin
Result := Self;
end;
function TDxBenDictionary.GetType: TDxBenValueTypes;
begin
Result := DBV_Dictionary;
end;
function TDxBenDictionary.GetValues(Key: string): TDxBenValue;
begin
if FDict.ContainsKey(Key) then
Result := FDict[Key]
else Result := nil;
end;
procedure TDxBenDictionary.Parser(str: string);
var
len: Integer;
p: PChar;
begin
len := Length(str);
Clear;
if (UpperCase(str[1]) = 'D') and (UpperCase(str[len]) = 'E') then
begin
Str := Copy(str,2,len - 2);
p := @str[1];
ParserToDictionary(p,Self);
end
else raise Exception.Create('无效的B编码字典格式');
end;
procedure TDxBenDictionary.ParserToDictionary(var p: PChar;
Dict: TDxBenDictionary);
type
TParserState = (PS_None,PS_Key,PS_Value);
var
t: Char;
st: string;
FInt: Integer;
IntValue: TDxBenInt;
ListValue: TDxBenList;
StrValue: TDxBenString;
DicValue: TDxBenDictionary;
Parstate: TParserState;
key: string;
begin
//开始解析
Parstate := PS_None;
while p^ <> '' do
begin
t := P^;
case t of
'i':
begin
//整数
if Parstate <> PS_Value then
raise Exception.Create('B编码字典的Key必须是字符串!');
Inc(p);
st := '';
while p^ <> 'e' do
begin
if not CharInSet(p^, ['-','0'..'9']) then
raise Exception.Create('无效的数据类型');
st := st p^;
Inc(p);
end;
if not TryStrToInt(st,FInt) then
raise Exception.Create('无效的数据类型i' st 'e');
IntValue := TDxBenInt.Create;
IntValue.FValue := FInt;
IntValue.FParent := Dict;
Dict.FDict[Key] := IntValue;
Inc(p);
Parstate := PS_None;
end;
'l':
begin
if Parstate <> PS_Value then
raise Exception.Create('B编码字典的Key必须是字符串!');
Inc(p);
ListValue := TDxBenList.Create;
ListValue.FParent := Dict;
Dict.FDict[Key] := ListValue;
ParserToList(p,ListValue);
Parstate := PS_None;
end;
'd':
begin
if Parstate <> PS_Value then
raise Exception.Create('B编码字典的Key必须是字符串!');
Inc(p);
DicValue := TDxBenDictionary.Create;
DicValue.FParent := Dict;
Dict.FDict[Key] := DicValue;
ParserToDictionary(p,DicValue);
Parstate := PS_None;
end;
'e':
begin
if Parstate = PS_Value then
Parstate := PS_None
else if Parstate = PS_None then
Break;
end;
else
begin
st := '';
while p^ <> ':' do
begin
if not CharInSet(p^, ['-','0'..'9']) then
raise Exception.Create('无效的数据类型');
st := st p^;
Inc(p);
end;
if not TryStrToInt(st,FInt) then
raise Exception.Create('无效的数据类型' st);
//读取字符串
Inc(p);
if StrLen(p) < FInt then
raise Exception.Create('字符串解析长度不够');
SetLength(st,Fint);
Move(p^,Pointer(St)^,FInt*Sizeof(Char));
Inc(p,Fint);
if Parstate = PS_None then
begin
key := st;
if Dict.FDict.ContainsKey(st) then
raise Exception.Create('字典存在重复信息');
Dict.FDict.Add(st,nil);
Parstate := PS_Value;
end
else if Parstate = PS_Value then
begin
StrValue := TDxBenString.Create;
StrValue.FParent := Dict;
StrValue.FValue := st;
Dict.FDict[Key] := StrValue;
Parstate := PS_None;
end;
end;
end;
end;
end;
procedure TDxBenDictionary.ParserToList(var P: Pchar; List: TDxBenList);
var
t: Char;
st: string;
FInt: Integer;
IntValue: TDxBenInt;
ListValue: TDxBenList;
StrValue: TDxBenString;
DicValue: TDxBenDictionary;
begin
//开始解析
while p^ <> '' do
begin
t := P^;
case t of
'i':
begin
//是一个整数
Inc(p);
st := '';
while p^ <> 'e' do
begin
if not CharInSet(p^, ['-','0'..'9']) then
raise Exception.Create('无效的数据类型');
st := st p^;
Inc(p);
end;
if not TryStrToInt(st,FInt) then
raise Exception.Create('无效的数据类型i' st 'e');
IntValue := TDxBenInt.Create;
IntValue.FValue := FInt;
IntValue.FParent := List;
List.FList.Add(IntValue);
Inc(p);
end;
'l':
begin
//列表
Inc(p);
ListValue := TDxBenList.Create;
ListValue.FParent := List;
List.FList.Add(ListValue);
ParserToList(p,ListValue);
end;
'd':
begin
//字典
Inc(p);
DicValue := TDxBenDictionary.Create;
DicValue.FParent := List;
List.FList.Add(DicValue);
ParserToDictionary(p,DicValue);
end;
'e': Break;//结束了
else
begin
//字符串
st := '';
while p^ <> ':' do
begin
if not CharInSet(p^, ['-','0'..'9']) then
raise Exception.Create('无效的数据类型');
st := st p^;
Inc(p);
end;
if not TryStrToInt(st,FInt) then
raise Exception.Create('无效的数据类型' st);
//读取字符串
Inc(p);
if StrLen(p) < FInt then
raise Exception.Create('字符串解析长度不够');
StrValue := TDxBenString.Create;
SetLength(StrValue.FValue,Fint);
Move(p^,Pointer(StrValue.FValue)^,FInt*Sizeof(Char));
StrValue.FParent := List;
List.FList.Add(StrValue);
Inc(p,Fint);
end;
end;
end;
end;
function TDxBenDictionary.ToString: string;
begin
end;
{ TDxTorrentFile }
procedure TDxTorrentFile.Clear;
begin
FDict.Clear;
end;
constructor TDxTorrentFile.Create;
begin
inherited;
FDict := TDxBenDictionary.Create;
end;
destructor TDxTorrentFile.Destroy;
begin
FDict.Free;
inherited;
end;
function TDxTorrentFile.Getannounce: string;
var
F: TDxBenValue;
begin
F := FDict.Values['announce'];
if F <> nil then
Result := F.AsString
else Result := '';
end;
function TDxTorrentFile.Getannounce_list: TDxBenList;
begin
Result := TDxBenList(FDict.Values['announce-list']);
end;
function TDxTorrentFile.GetBtInfo: TDxBtInfo;
begin
Result := TDxBtInfo(FDict.Values['info']);
end;
function TDxTorrentFile.GetComment: string;
begin
if FDict.FDict.ContainsKey('comment') then
begin
if CompareText(Encoding,'utf-8') = 0 then
Result := UTF8Decode(FDict.Values['comment'].AsString)
else result := FDict.Values['comment'].AsString
end
else result := '';
end;
function SpanOfNowAndThen(const ANow, AThen: TDateTime): TDateTime;
begin
if ANow < AThen then
Result := AThen - ANow
else
Result := ANow - AThen;
end;
function SecondSpan(const ANow, AThen: TDateTime): Double;
begin
Result := SecsPerDay * SpanOfNowAndThen(ANow, AThen);
end;
function TDxTorrentFile.GetCreateDate: TDateTime;
var
F: TDxBenValue;
V: Double;
begin
F := FDict.Values['creation date'];
if F <> nil then
begin //是从1970年1月1日00:00:00到现在的秒数
Result := F.AsInteger;
//V := StrToDate('1970-01-01');//25569
V := SecondSpan(Now,25569);
V := (V - Result) / SecsPerDay;
Result := Now - V
end
else Result := 0;
end;
function TDxTorrentFile.GetCreator: string;
var
F: TDxBenValue;
begin
F := FDict.Values['created by'];
if F <> nil then
Result := F.AsString
else Result := '';
end;
function TDxTorrentFile.GetEncoding: string;
begin
if FDict.Values['encoding'] <> nil then
Result := FDict.Values['encoding'].AsString
else result := '';
end;
procedure TDxTorrentFile.LoadFromFile(FileName: string);
var
F: TFileStream;
begin
F := TFileStream.Create(FileName,fmOpenRead);
LoadFromStream(F);
F.Free;
end;
procedure TDxTorrentFile.LoadFromStream(Stream: TStream);
var
c: Byte;
begin
Clear;
Stream.ReadBuffer(c,1);
if Char(c) = 'd' then
ParserStream(Stream,FDict);
end;
procedure TDxTorrentFile.ParserStreamToList(Stream: TStream; List: TDxBenList);
var
t: Byte;
st: Ansistring;
FInt: Integer;
IntValue: TDxBenInt;
ListValue: TDxBenList;
StrValue: TDxBenString;
DicValue: TDxBenDictionary;
begin
while Stream.Position <> Stream.Size do
begin
Stream.ReadBuffer(t,SizeOf(t));
case Char(t) of
'i':
begin
//是一个整数
st := '';
Stream.ReadBuffer(t,SizeOf(t));
while Char(t) <> 'e' do
begin
if not CharInSet(Char(t), ['-','0'..'9']) then
raise Exception.Create('无效的数据类型');
st := st Char(t);
end;
if not TryStrToInt(st,FInt) then
raise Exception.Create('无效的数据类型i' st 'e');
IntValue := TDxBenInt.Create;
IntValue.FValue := FInt;
IntValue.FParent := List;
List.FList.Add(IntValue);
end;
'l':
begin
//列表
ListValue := TDxBenList.Create;
ListValue.FParent := List;
List.FList.Add(ListValue);
ParserStreamToList(Stream,ListValue);
end;
'd':
begin
DicValue := TDxBenDictionary.Create;
DicValue.FParent := List;
List.FList.Add(DicValue);
ParserStream(Stream,DicValue);
end;
'e': Break;
else
begin
st := '';
while Char(t) <> ':' do
begin
if not CharInSet(Char(t), ['-','0'..'9']) then
raise Exception.Create('无效的数据类型');
st := st Char(t);
Stream.ReadBuffer(t,SizeOf(t));
end;
if not TryStrToInt(st,FInt) then
raise Exception.Create('无效的数据类型' st);
//读取字符串
if Stream.Size - Stream.Position < FInt then
raise Exception.Create('字符串解析长度不够');
SetLength(st,Fint);
Stream.ReadBuffer(Pointer(st)^,Fint);
StrValue := TDxBenString.Create;
if CompareText(Encoding,'utf-8') = 0 then
StrValue.FValue := UTF8Decode(st)
else StrValue.FValue := st;
StrValue.FParent := List;
List.FList.Add(StrValue);
end;
end;
end;
end;
procedure TDxTorrentFile.ParserStream(Stream: TStream;Dict: TDxBenDictionary);
type
TParserState = (PS_None,PS_Key,PS_Value);
var
t: Byte;
st: Ansistring;
FInt: Integer;
IntValue: TDxBenInt;
ListValue: TDxBenList;
StrValue: TDxBenString;
DicValue: TDxBenDictionary;
Parstate: TParserState;
key: string;
begin
Parstate := PS_None;
while Stream.Position < Stream.Size do
begin
Stream.ReadBuffer(t,SizeOf(t));
case Char(t) of
'i':
begin
if Parstate <> PS_Value then
raise Exception.Create('B编码字典的Key必须是字符串!');
st := '';
Stream.ReadBuffer(t,SizeOf(t));
while Char(t) <> 'e' do
begin
if not CharInSet(Char(t), ['-','0'..'9']) then
raise Exception.Create('无效的数据类型');
st := st Char(t);
Stream.ReadBuffer(t,SizeOf(t));
end;
if not TryStrToInt(st,FInt) then
raise Exception.Create('无效的数据类型i' st 'e');
IntValue := TDxBenInt.Create;
IntValue.FValue := FInt;
IntValue.FParent := Dict;
Dict.FDict[Key] := IntValue;
Parstate := PS_None;
end;
'l':
begin
if Parstate <> PS_Value then
raise Exception.Create('B编码字典的Key必须是字符串!');
ListValue := TDxBenList.Create;
ListValue.FParent := Dict;
Dict.FDict[Key] := ListValue;
ParserStreamToList(Stream,ListValue);
Parstate := PS_None;
end;
'd':
begin
if Parstate <> PS_Value then
raise Exception.Create('B编码字典的Key必须是字符串!');
DicValue := TDxBenDictionary.Create;
DicValue.FParent := Dict;
Dict.FDict[Key] := DicValue;
ParserStream(stream,DicValue);
Parstate := PS_None;
end;
'e':
begin
if Parstate = PS_Value then
Parstate := PS_None
else if Parstate = PS_None then
Break;
end;
else
begin
st := '';
while Char(t) <> ':' do
begin
if not CharInSet(Char(t), ['-','0'..'9']) then
raise Exception.Create('无效的数据类型');
st := st Char(t);
Stream.ReadBuffer(t,SizeOf(t));
end;
if not TryStrToInt(st,FInt) then
raise Exception.Create('无效的数据类型' st);
if Stream.Size - Stream.Position < FInt then
raise Exception.Create('字符串解析长度不够');
SetLength(st,Fint);
Stream.ReadBuffer(Pointer(st)^,Fint);
if Parstate = PS_None then
begin
key := st;
if Dict.FDict.ContainsKey(st) then
raise Exception.Create('字典存在重复信息');
Dict.FDict.Add(st,nil);
Parstate := PS_Value;
end
else if Parstate = PS_Value then
begin
StrValue := TDxBenString.Create;
StrValue.FParent := Dict;
if CompareText(Encoding,'utf-8') = 0 then
StrValue.FValue := UTF8Decode(st)
else StrValue.FValue := st;
Dict.FDict[Key] := StrValue;
Parstate := PS_None;
end;
end;
end;
end;
end;
{ TDxBtInfo }
function TDxBtInfo.GetFiles: TDxBenList;
begin
Result := TDxBenList(Values['files'])
end;
function TDxBtInfo.GetName: string;
var
F: TDxBenValue;
begin
F := Values['name'];
if F <> nil then
Result := F.AsString
else Result := '';
end;
function TDxBtInfo.GetNameUtf8: string;
var
F: TDxBenValue;
begin
F := Values['name.utf-8'];
if F <> nil then
Result := F.AsString
else Result := '';
end;
function TDxBtInfo.Getpublisher: string;
var
F: TDxBenValue;
begin
F := Values['publisher'];
if F <> nil then
Result := F.AsString
else Result := '';
end;
function TDxBtInfo.Getpublisherurl: string;
var
F: TDxBenValue;
begin
F := Values['publisher-url'];
if F <> nil then
Result := F.AsString
else Result := '';
end;
function TDxBtInfo.GetpublisherurlUtf8: string;
var
F: TDxBenValue;
begin
F := Values['publisher-url.utf8'];
if F <> nil then
Result := F.AsString
else Result := '';
end;
function TDxBtInfo.GetpublisherUtf8: string;
var
F: TDxBenValue;
begin
F := Values['publisher.utf-8'];
if F <> nil then
Result := F.AsString
else Result := '';
end;
function TDxBtInfo.GetSingleFile: Boolean;
begin
Result := Files = nil;
end;
end.