📄 torrentfile.pas
字号:
unit TorrentFile;
interface
uses
SysUtils, StrUtils, Contnrs, Hashes, Classes, BCode, MessageDigests, TSpyUtil;
type
TProgressCallback = function(PieceNum: Integer): Boolean of object;
TTorrentPiece = class(TObject)
private
_Hash: string;
_Valid: Boolean;
public
property Hash: string read _Hash;
property Valid: Boolean read _Valid write _Valid;
constructor Create(Hash: string; Valid: Boolean);
end;
TTorrentSubFile = class(TObject)
private
_Name: string;
_Path: string;
_Length: Int64;
_Offset: Int64;
_Left: Int64;
_MD5Sum: string;
_MD4Sum: string;
_SHA1Sum: string;
public
property Name: string read _Name;
property Path: string read _Path;
property Len: Int64 read _Length;
property Offset: Int64 read _Offset;
property Left: Int64 read _Left write _Left;
property MD5Sum: string read _MD5Sum;
property MD4Sum: string read _MD4Sum;
property SHA1Sum: string read _SHA1Sum;
constructor Create(Name: string; Path: string; Len: Int64; Offset: Int64; MD5Sum, SHA1Sum, MD4Sum: string);
end;
TTorrentFile = class(TObject)
published
private
_Announce: string;
_AnnounceList: TObjectList;
_Name: string;
_Length: Int64;
_Count: Integer;
_Files: TObjectList;
_Err: TStringList;
_Tree: TObjectHash;
_SHA1Hash: string;
_MD5Hash: string;
_MD4Hash: string;
_InfoHash: string;
_PieceLength: Integer;
_Multifile: Boolean;
_BinaryHash: string;
_Comment: string;
_CreationDate: Int64;
_CreationDateAsString: string;
_CreatedBy: string;
_PathDelim: string;
public
Pieces: array of TTorrentPiece;
property Announce: string read _Announce write _Announce;
property AnnounceList: TObjectList read _AnnounceList write _AnnounceList;
property Name: string read _Name write _Name;
property Len: Int64 read _Length;
property Count: Integer read _Count;
property Tree: TObjectHash read _Tree;
property Errors: TStringList read _Err;
property Hash: string read _InfoHash;
property BinaryHash: string read _BinaryHash;
property Files: TObjectList read _Files;
property PieceLength: Integer read _PieceLength write _PieceLength;
property Multifile: Boolean read _Multifile;
property Comment: string read _Comment write _Comment;
property CreationDate: Int64 read _CreationDate;
property CreationDateAsString: string read _CreationDateAsString;
property CreatedBy: string read _CreatedBy write _CreatedBy;
property PathDelim: string read _PathDelim;
procedure Clear();
function Load(Stream: TStream): Boolean;
function Save(Stream: TStream): Boolean;
constructor Create();
destructor Destroy(); override;
function MakePieces(CallbackProc: TProgressCallback; FileList: TObjectList): Integer;
end;
implementation
function SortFiles(A, B: Pointer): Integer;
begin
Result := CompareStr(TTorrentSubFile(A).Path, TTorrentSubFile(B).Path);
end;
{ TTorrentSubFile }
constructor TTorrentSubFile.Create(Name, Path: string; Len: Int64; Offset: Int64; MD5Sum, SHA1Sum, MD4Sum: string);
begin
_Name := Name;
_Path := Path;
_Length := Len;
_Offset := Offset;
_Left := Len;
_MD5Sum := MD5Sum;
_MD4Sum := MD4Sum;
_SHA1Sum := SHA1Sum;
inherited Create();
end;
{ TTorrentFile }
procedure TTorrentFile.Clear();
var
i: Integer;
begin
_Announce := '';
_AnnounceList.Clear();
_Name := '';
_InfoHash := '';
_SHA1Hash := '';
_MD5Hash := '';
_MD4Hash := '';
_Length := 0;
_Count := 0;
_Files.Clear();
_Tree.Clear();
_Err.Clear();
_BinaryHash := '';
_Comment := '';
_CreationDate := 0;
_CreationDateAsString := '';
_CreatedBy := '';
for i := Low(Pieces) to High(Pieces) do FreeAndNil(Pieces[i]);
SetLength(Pieces, 0);
_Multifile := False;
end;
constructor TTorrentFile.Create();
begin
_Files := TObjectList.Create();
_Tree := TObjectHash.Create();
_Err := TStringList.Create();
_AnnounceList := TObjectList.Create();
_PathDelim := (IncludeTrailingPathDelimiter('.'))[2];
inherited Create();
end;
destructor TTorrentFile.Destroy();
begin
Clear();
FreeAndNil(_Files);
FreeAndNil(_Tree);
FreeAndNil(_Err);
FreeAndNil(_AnnounceList);
inherited;
end;
function TTorrentFile.Load(Stream: TStream): Boolean;
var
info, thisfile: TObjectHash;
files, path, announcelist, announcetier: TObjectList;
thistier: TStringList;
fp, fn, bh, md5sum, md4sum, sha1sum: string;
i, j, pcount: Integer;
sz, fs, fo: Int64;
sha: TSHA1;
r: Boolean;
o: TObject;
p: PChar;
begin
Clear();
r := False;
sz := 0;
try
try
o := bdecodeStream(Stream);
if (Assigned(o)) then begin
_Tree := o as TObjectHash;
if (_Tree.Exists('announce')) then
if _Tree['announce'] is TString then
_Announce := (_Tree['announce'] as TString).Value
else
_Err.Add('Corrupt file: The "announce" segment should be a string')
else
_Err.Add('Corrupt File: Missing "announce" segment');
if (_Tree.Exists('announce-list')) then begin
if _Tree['announce-list'] is TObjectList then begin
announcelist := _Tree['announce-list'] as TObjectList;
for i := 0 to announcelist.Count - 1 do begin
if announcelist[i] is TObjectList then begin
announcetier := announcelist[i] as TObjectList;
thistier := TStringList.Create();
for j := 0 to announcetier.Count - 1 do
if announcetier[j] is TString then
thistier.Add((announcetier[j] as TString).Value)
else
_Err.Add('Corrupt file: The entries in each tier of the "announce-list" segment should be strings');
if thistier.Count > 0 then begin
_AnnounceList.Add(thistier);
thistier := nil;
end else
FreeAndNil(thistier);
end else begin
_Err.Add('Corrupt file: The tiers in the "announce-list" segment should also be lists ')
end; // if is a list
end; // for i
end else begin
_Err.Add('Corrupt file: The "announce-list" segment should be a list');
end; // if is an object list
end; // if has key
if (_Tree.Exists('creation date')) then
if _Tree['creation date'] is TInt64 then
_CreationDate := (_Tree['creation date'] as TInt64).Value
else if _Tree['creation date'] is TString then
_CreationDateAsString := (_Tree['creation date'] as TString).Value
else
_Err.Add('Corrupt file: The "creation date" segment should be an integer');
if (_Tree.Exists('created by')) then
if _Tree['created by'] is TString then
_CreatedBy := (_Tree['created by'] as TString).Value
else
_Err.Add('Corrupt file: The "created by" segment should be a string');
if (_Tree.Exists('user-agent')) then
if _Tree['user-agent'] is TString then
_CreatedBy := (_Tree['user-agent'] as TString).Value
else
_Err.Add('Corrupt file: The "user-agent" segment should be a string');
if (_Tree.Exists('comment')) then
if _Tree['comment'] is TString then
_Comment := (_Tree['comment'] as TString).Value
else
_Err.Add('Corrupt File: The "comment" segment should be a string');
if (_Tree.Exists('info')) then begin
if _Tree['info'] is TObjectHash then begin
info := _Tree['info'] as TObjectHash;
if (info.Exists('name')) then begin
if info['name'] is TString then
_Name := (info['name'] as TString).Value
else
_Err.Add('Corrupt File: The "info.name" segment should be a string')
end else begin
_Err.Add('Corrupt File: Missing "info.name" segment');
end;
if (info.Exists('piece length')) then begin
if info['piece length'] is TInt64 then
_PieceLength := (info['piece length'] as TInt64).Value
else
_Err.Add('Corrupt File: The "info.piece length" segment should be an integer');
end else begin
_Err.Add('Corrupt File: Missing "info.piece length" segment');
end;
if (info.Exists('pieces')) then begin
if info['pieces'] is TString then begin
//fp := (info['pieces'] as TString).Value;
//pcount := Length(fp);
//pcount := pcount div 20;
//SetLength(Pieces,pcount);
//注释掉
//for i := 0 to pcount - 1 do begin
// Pieces[i] := TTorrentPiece.Create(bin2hex(MidStr(fp,(i * 20) + 1,20)), False);
//end;
end else
_Err.Add('Corrupt File: The "info.pieces" segment should be a string');
end else begin
_Err.Add('Corrupt File: Missing "info.pieces" segment');
end;
if (info.Exists('length')) then begin // single-file archive
if info['length'] is TInt64 then begin
sz := (info['length'] as TInt64).Value;
_Count := 1;
md5sum := '';
if (info.Exists('md5sum')) then
if info['md5sum'] is TString then
md5sum := (info['md5sum'] as TString).Value
else
_Err.Add('Corrupt File: The "info.md5sum" segment should be a string');
md4sum := '';
if (info.Exists('ed2k')) then
if info['ed2k'] is TString then
md4sum := (info['ed2k'] as TString).Value
else
_Err.Add('Corrupt File: The "info.ed2k" segment should be a string');
sha1sum := '';
if (info.Exists('sha1')) then
if info['sha1'] is TString then
sha1sum := (info['sha1'] as TString).Value
else
_Err.Add('Corrupt File: The "info.sha1" segment should be a string');
_Files.Add(TTorrentSubFile.Create(_Name, '', sz, Int64(0), md5sum, sha1sum, md4sum));
end else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -