⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 torrentfile.pas

📁 分析torrent的东西是拿别人的
💻 PAS
📖 第 1 页 / 共 2 页
字号:
                _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 + -