Delphi,如何使用BEncode获取info_hash?

时间:2015-12-08 14:07:01

标签: delphi torrent

我想使用Delphi获取* .torrent文件的info_hash。 试过this BEncode decorder。 但它在解码时会给出疯狂的角色。 Delphi中的任何其他工作BEncode解码器?或者我做错了什么? 这是我的代码:

procedure TForm.Button1Click(Sender: TObject);
var
 be: TBEncoded;
 fs: tfilestream;
 op: string;
begin
 fs := tfilestream.Create('xx.torrent', fmOpenReadWrite);
 be := TBEncoded.Create(fs);

 be.Encode(be.ListData.Items[0].Data, op);
 showmessage(op);

 be.Encode(be.ListData.FindElement('info'), op);
 showmessage(op);
end;

1 个答案:

答案 0 :(得分:3)

我刚试过这个解码器,它正常工作。您不需要使用Encode程序,其目的(从名称上看)是将元素编码回BEncode。该测试程序在TMemo中显示了torrent信息:

procedure ShowDecoded(be: TBEncoded; indent: string='');
var i: Integer;
begin
  with form1.Memo1.Lines do
    case be.Format of
      befstring: Add(indent+be.StringData);
      befInteger: Add(indent+IntToStr(be.IntegerData));
      befList: begin
        Add(indent+'list');
        for i:=0 to be.ListData.Count-1 do
          ShowDecoded(be.ListData.Items[i].Data as TBEncoded,indent+'   ');
        Add(indent+'end of list');
      end;
      befDictionary: begin
        Add(indent+'dict');
        for i:=0 to be.ListData.Count-1 do begin
          Add(indent+'   '+be.ListData.Items[i].Header+'=');
          ShowDecoded(be.listData.Items[i].Data as TBEncoded,indent+'      ');
        end;
        Add(indent+'end of dict');
      end;
    end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var fs: TFileStream;
    be: TBEncoded;
    i: Integer;
begin
  if OpenDialog1.Execute then begin
    fs:=TFileStream.Create(OpenDialog1.FileName,fmOpenRead);
    try
      be:=TBEncoded.Create(fs);
      ShowDecoded(be);  
      be.Free;
    finally
      fs.Free;
    end;
  end;
end;

该测试结果:

dict
   created by=
      uTorrent/3.4.3
   creation date=
      1439626950
   encoding=
      UTF-8
   info=
      dict
         length=
            1345178
         name=
            Алябьев А., Лист Ф. - Соловей - 1987.pdf
         piece length=
            16384
         pieces=
            )Lo.Î ’üXí»IÙçsáôt£ˆb›hŒˆ*Ð誺š¤/N7’`0âÓ†nË5&T€:V•Ìפ¯9¤Ý:¦J©Ï|Œ•A¥,¼R¯þ:H:X&…¢<¸º"2îV-vÀÖˆD†¨¬ß‰ƒ,ümjà?éÛoe¬r£{¨¾]•4òØžhô†›­¼AØBeJÕÌ4³·Œ‹¶ËAG— f„\pa
      end of dict
end of dict

我对BEncode单元进行了一些更改,其中有一些混乱:引发空的异常,不安全的转换:TBEncoded(对象)而不是&#34;对象作为TBEncoded&#34;, 在object.free之前检查nil对象,这是重言式,但一般来说它都有效。

更新1 简单的代码,可以使用其中一个字段,&#39; pieces&#39;并以十六进制显示。

procedure FindAndShowHash(be: TBEncoded);
var i: Integer;
  s: string;
  infoChunk, piecesChunk: TBencoded;
begin
  s:='';
  infoChunk:=be.ListData.FindElement('info') as TBencoded;
  piecesChunk:=infoChunk.ListData.FindElement('pieces') as TBencoded;
  for i:=1 to Length(piecesChunk.StringData) do
    s:=s+IntToHex(Byte(piecesChunk.StringData[i]),2);
  form1.Memo1.Lines.Add('Hash function:');
  form1.Memo1.Lines.Add(s);
end;

如您所见,我们通过char访问StringData char并将其转换为Byte。我只是用十六进制显示它,当然你可以使用这些字节进行进一步处理。

注意:您将获得十六进制值的LOADS,这不是MD5哈希或WHOLE torrent的任何其他哈希,它是每个数据的哈希函数序列,通常是1或2的块MB。

更新2

这个单元可以在较新版本的Delphi中使用,你需要做的就是从&#39; string&#39;中替换其中的所有字符串变量。到&#39; ANSIstring&#39;,只需使用Ctrl + R - &#39;:string&#39;替换为&#39;:ANSIstring&#39;。

更新3

好的,最后我明白了。这是计算info_hash并以十六进制显示的过程,这需要更新版本的Delphi。另外,添加IdGlobal和IdHashSHA以使用&#39;部分。

procedure makeInfoHash(be: TBEncoded);
var SHA1:  TIdHashSHA1;
    s: string;
    infoChunk: TBencoded;
    infoEncoded: ANSIString;
    bytes: TIdBytes;
begin
  infoChunk:=be.ListData.FindElement('info') as TBencoded;
  TBencoded.Encode(infoChunk,infoEncoded);
  bytes:=RawToBytes(infoEncoded[1],Length(infoEncoded));
  SHA1:=TIdHashSHA1.Create;
  try   
    s:=SHA1.HashBytesAsHex(bytes);
  finally
    SHA1.Free;
  end;
  Form1.Memo1.Lines.Add(s);
end;

它提供了正确的info_hash,与uTorrent中显示的相同,如下所示:

7D0487D3D99D9C27A7C09CDCBB2F2A8034D4F9BF

您必须将所有字符串替换为BENcode.pas中的ANSIstring,如更新2中所述。享受!