📄 torrentfile.pas
字号:
_Err.Add('Corrupt File: The "info.length" segment should be an integer');
end else begin
if (info.Exists('files')) then begin
if info['files'] is TObjectList then begin
_Multifile := True;
files := info['files'] as TObjectList;
for i := 0 to files.Count - 1 do begin
thisfile := files[i] as TObjectHash;
fs := Int64(0);
if (thisfile.Exists('length')) then begin
if thisfile['length'] is TInt64 then
fs := (thisfile['length'] as TInt64).Value
else
_Err.Add('Corrupt File: files[' + IntToStr(i) + '].length should be an integer');
end else begin
_Err.Add('Corrupt File: files[' + IntToStr(i) + '] is missing a "length" segment');
end;
fp := '';
fn := '';
if (thisfile.Exists('path')) then begin
if thisfile['path'] is TObjectList then begin
path := thisfile['path'] as TObjectList;
for j := 0 to path.Count - 2 do
if path[j] is TString then
fp := fp + (path[j] as TString).Value + _PathDelim
else
_Err.Add('Corrupt File: files[' + IntToStr(i) + '].path[' + IntToStr(j) + '] should be a string');
if path[path.Count - 1] is TString then
fn := (path[path.Count - 1] as TString).Value;
end else
_Err.Add('Corrupt File: files[' + IntToStr(i) + '].path should be a list');
end else begin
_Err.Add('Corrupt File: files[' + IntToStr(i) + '] is missing a "path" segment');
end;
md5sum := '';
if (thisfile.Exists('md5sum')) then
if thisfile['md5sum'] is TString then
md5sum := (thisfile['md5sum'] as TString).Value
else
_Err.Add('Corrupt File: files[' + IntToStr(i) + '].md5sum should be a string');
md4sum := '';
if (thisfile.Exists('ed2k')) then
if thisfile['ed2k'] is TString then
md4sum := (thisfile['ed2k'] as TString).Value
else
_Err.Add('Corrupt File: files[' + IntToStr(i) + '].ed2k should be a string');
sha1sum := '';
if (thisfile.Exists('sha1')) then
if thisfile['sha1'] is TString then
sha1sum := (thisfile['sha1'] as TString).Value
else
_Err.Add('Corrupt File: files[' + IntToStr(i) + '].sha1 should be a string');
_Files.Add(TTorrentSubFile.Create(fn, fp, fs, sz, md5sum, sha1sum, md4sum));
sz := sz + fs;
end;
_Count := files.Count;
end else
_Err.Add('Corrupt File: Missing both "info.length" and "info.files" segments (should have one or the other)');
end else
_Err.Add('Corrupt File: The "files" segment should be a list');
end;
if (_Tree.Exists('_info_start') and _Tree.Exists('_info_length')) then begin
fo := Stream.Position;
Stream.Seek((_Tree['_info_start'] as TInt64).Value, soFromBeginning);
fs := (_Tree['_info_length'] as TInt64).Value;
SetLength(fp, fs);
Stream.Read(PChar(fp)^, fs);
sha := TSHA1.Create();
sha.TransformString(fp);
sha.Complete();
_InfoHash := sha.HashValue();
SetLength(bh, sha.DigestSize);
p := sha.HashValueBytes();
for i := 1 to sha.DigestSize do begin
bh[i] := Char(p^);
Inc(p);
end;
_BinaryHash := bh;
Stream.Seek(fo, soFromBeginning);
end;
end else
_Err.Add('Corrupt File: The "info" segment should be a dictionary');
end else begin
_Err.Add('Corrupt File: Missing "info" segment');
end;
_Length := sz;
r := True;
end else begin
_Err.Add('Error parsing file; does not appear to be valid bencoded metainfo');
end;
finally
FreeAndNil(sha);
end;
except
_Err.Add('Something bad happened while trying to load the file, probably corrupt metainfo');
end;
Result := r;
end;
function TTorrentFile.MakePieces(CallbackProc: TProgressCallback; FileList: TObjectList): Integer;
var
FileNum, PCount, PID: Integer;
NumFiles: Integer;
FileLeft, PieceLeft, didRead, toRead, FileSize, Offset: Int64;
buf, FilePath, FileName, FullPath, RelativePath: string;
sha, all_sha, file_sha: TSHA1;
md5, all_md5: TMD5;
md4, all_md4: TMD4;
isRunning: Boolean;
TheFile: TObjectHash;
InFile: TFileStream;
begin
Clear();
NumFiles := 0;
_Length := 0;
for FileNum := 0 to FileList.Count - 1 do _Length := _Length + ((FileList[FileNum] as TObjectHash)['length'] as TInt64).Value;
_Count := FileList.Count;
FileNum := 0;
sha := TSHA1.Create();
all_sha := TSHA1.Create();
file_sha := TSHA1.Create();
md5 := TMD5.Create();
all_md5 := TMD5.Create();
md4 := TMD4.Create();
all_md4 := TMD4.Create();
SetLength(buf, _PieceLength);
PCount := _Length div _PieceLength;
if (PCount * _PieceLength < _Length) then PCount := PCount + 1;
SetLength(Pieces, PCount);
PieceLeft := _PieceLength;
PID := 0;
isRunning := True;
Offset := 0;
try
while (isRunning and (FileNum < FileList.Count)) do begin
TheFile := FileList[FileNum] as TObjectHash;
FullPath := (TheFile['_'] as TString).Value;
RelativePath := (TheFile['path'] as TString).Value;
FileName := ExtractFileName(FullPath);
FilePath := ExtractFilePath(FullPath);
FileSize := (TheFile['length'] as TInt64).Value;
FileLeft := FileSize;
try
InFile := TFileStream.Create(FullPath, fmOpenRead, fmShareDenyNone);
except
raise Exception.Create('Could not open the input file for read access.' + #13 + #10 + FilePath);
end;
while (isRunning and (FileLeft > 0)) do begin
if (FileLeft < PieceLeft) then toRead := FileLeft else toRead := PieceLeft;
didRead := InFile.Read(PChar(buf)^, toRead);
if (didRead <> toRead) then raise Exception.Create('End of file before expected:' + #13 + #10 + FilePath);
sha.Transform(PChar(buf)^, didRead);
md5.Transform(PChar(buf)^, didRead);
md4.Transform(PChar(buf)^, didRead);
all_sha.Transform(PChar(buf)^, didRead);
all_md5.Transform(PChar(buf)^, didRead);
all_md4.Transform(PChar(buf)^, didRead);
file_sha.Transform(PChar(buf)^, didRead);
FileLeft := FileLeft - didRead;
PieceLeft := PieceLeft - didRead;
if (PieceLeft < 1) then begin
sha.Complete();
Pieces[PID] := TTorrentPiece.Create(sha.HashValue(), True);
Inc(PID);
sha.Clear();
PieceLeft := _PieceLength;
end;
isRunning := CallbackProc(PID);
end;
FreeAndNil(InFile);
Inc(FileNum);
TheFile.Delete('_');
md5.Complete();
md4.Complete();
file_sha.Complete();
_Files.Add(TTorrentSubFile.Create(FileName, RelativePath, FileSize, Offset, md5.HashValue(), file_sha.HashValue(), md4.HashValue()));
Offset := Offset + FileSize;
_Length := _Length + FileSize;
md5.Clear();
md4.Clear();
file_sha.Clear();
end;
if (PieceLeft <> _PieceLength) then begin
sha.Complete();
Pieces[PID] := TTorrentPiece.Create(sha.HashValue(), True);
sha.Clear();
CallbackProc(PCount);
end;
all_sha.Complete();
all_md5.Complete();
all_md4.Complete();
_SHA1Hash := all_sha.HashValue();
_MD5Hash := all_md5.HashValue();
_MD4Hash := all_md4.HashValue();
finally
FreeAndNil(InFile);
FreeAndNil(sha);
FreeAndNil(md5);
FreeAndNil(md4);
FreeAndNil(file_sha);
FreeAndNil(all_md5);
FreeAndNil(all_md4);
FreeAndNil(all_sha);
end;
if (NumFiles > 1) then _MultiFile := True;
_CreationDate := UnixTime();
Result := _Count;
end;
function TTorrentFile.Save(Stream: TStream): Boolean;
var
Root, Info, NF: TObjectHash;
F: TTorrentSubFile;
FileList, AList, TList: TObjectList;
tier: TStringList;
P: TStringList;
PBuf, Hash: string;
i, j, k: Integer;
begin
Root := TObjectHash.Create();
Root['announce'] := TString.Create(_Announce);
Info := TObjectHash.Create();
Root['info'] := Info;
Info['name'] := TString.Create(_Name);
if (_Count > 1) then begin
FileList := TObjectList.Create();
_Files.Sort(SortFiles);
Info['files'] := FileList;
for i := 0 to _Files.Count - 1 do begin
F := _Files[i] as TTorrentSubFile;
P := TStringList.Create();
Split(F.Path, P, _PathDelim);
NF := TObjectHash.Create();
NF['length'] := TInt64.Create(F.Len);
NF['path'] := P;
if (Length(F.MD5Sum) > 0) then NF['md5sum'] := TString.Create(F.MD5Sum);
if (Length(F.MD4Sum) > 0) then NF['ed2k'] := TString.Create(hex2bin(F.MD4Sum));
if (Length(F.SHA1Sum) > 0) then NF['sha1'] := TString.Create(hex2bin(F.SHA1Sum));
FileList.Add(NF);
end;
end else begin
F := Files[0] as TTorrentSubFile;
Info['length'] := TInt64.Create(F.Len);
if (Length(F.MD5Sum) > 0) then Info['md5sum'] := TString.Create(F.MD5Sum);
if (Length(F.MD4Sum) > 0) then Info['ed2k'] := TString.Create(hex2bin(F.MD4Sum));
if (Length(F.SHA1Sum) > 0) then Info['sha1'] := TString.Create(hex2bin(F.SHA1Sum));
end;
Info['piece length'] := TInt64.Create(_PieceLength);
SetLength(PBuf, 20 * Length(Pieces));
for i := 0 to Length(Pieces) - 1 do begin
k := i * 20;
Hash := hex2bin(Pieces[i].Hash);
for j := 1 to 20 do begin
PBuf[k + j] := Hash[j];
end;
end;
Info['pieces'] := TString.Create(PBuf);
Root['created by'] := TString.Create(_CreatedBy);
Root['creation date'] := TInt64.Create(_CreationDate);
if Length(_Comment) > 0 then Root['comment'] := TString.Create(_Comment);
if Length(_MD5Hash) > 0 then Info['md5sum'] := TString.Create(_MD5Hash);
if Length(_MD4Hash) > 0 then Info['ed2k'] := TString.Create(hex2bin(_MD4Hash));
if Length(_SHA1Hash) > 0 then Info['sha1'] := TString.Create(hex2bin(_SHA1Hash));
if _AnnounceList.Count > 0 then begin
AList := TObjectList.Create();
for i := 0 to _AnnounceList.Count do begin
tier := _AnnounceList[i] as TStringList;
TList := TObjectList.Create();
for j := 0 to tier.Count do begin
TList.Add(TString.Create(tier[j]));
end; // for j
AList.Add(TList);
TList := nil;
end; // for i
Root['announce-list'] := AList;
AList := nil;
end; // if has announce-list
Result := bencodeStream(Root, Stream);
end;
{ TTorrentPiece }
constructor TTorrentPiece.Create(Hash: string; Valid: Boolean);
begin
_Hash := Hash;
_Valid := Valid;
inherited Create();
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -