📄 bcode.pas
字号:
unit BCode;
interface
uses
SysUtils, Classes, Contnrs, Hashes;
type
TBEType = (beInt64, beString, beList, beDicionary);
TInt64 = class(TOBject)
private
_Value: Int64;
public
property Value: Int64 read _Value write _Value;
constructor Create(Value: Int64);
end;
TString = class(TObject)
private
_Value: String;
public
property Value: String read _Value write _Value;
constructor Create(Value: String);
end;
function bencodeStream(Root: TObject; Stream: TStream): Boolean;
function bdecodeStream(s: TStream): TObject;
function bdecodeInt64(s: TStream): TInt64;
function bdecodeString(s: TStream; i: Integer = 0): TString;
function bdecodeHash(s: TStream): TObjectHash;
function bdecodeList(s: TStream): TObjectList;
implementation
function bencodeInt64(Root: TInt64; Stream: TStream): Boolean;
var
s: String;
l: Integer;
begin
s := 'i' + IntToStr(Root.Value) + 'e';
l := Length(s);
if (l = Stream.Write(PChar(s)^,l)) then Result := True else Result := False;
end;
function bencodeString(Root: TString; Stream: TStream): Boolean;
var
s: String;
l: Integer;
begin
s := IntToStr(Length(Root.Value)) + ':' + Root.Value;
l := Length(s);
if (l = Stream.Write(PChar(s)^,l)) then Result := True else Result := False;
end;
function bencodeList(Root: TObjectList; Stream: TStream): Boolean;
var
i: Integer;
s: String;
begin
s := 'l';
if (Stream.Write(PChar(s)^,1) = 1) then begin
for i := 0 to Root.Count - 1 do bencodeStream(Root[i],Stream);
s := 'e';
if (Stream.Write(PChar(s)^,1) = 1) then Result := True else Result := False;
end else Result := False;
end;
function bencodeStringList(Root: TStringList; Stream: TStream): Boolean;
var
i: Integer;
s: String;
begin
s := 'l';
if (Stream.Write(PChar(s)^,1) = 1) then begin
for i := 0 to Root.Count - 1 do bencodeString(TString.Create(Root[i]),Stream);
s := 'e';
if (Stream.Write(PChar(s)^,1) = 1) then Result := True else Result := False;
end else Result := False;
end;
function bencodeDictionary(Root: TObjectHash; Stream: TStream): Boolean;
var
sl: TStringList;
i: Integer;
s: TString;
t: String;
begin
t := 'd';
if (Stream.Write(PChar(t)^,1) = 1) then begin
sl := TStringList.Create();
Root.Restart();
while (Root.Next) do sl.Add(Root.CurrentKey);
sl.Sort(); // official spec requires dictionaries to be sorted by key
s := TString.Create('');
for i := 0 to sl.Count - 1 do begin
s.Value := sl[i];
if not bencodeString(s,Stream) then begin
Result := False;
FreeAndNil(sl);
Exit;
end;
if not bencodeStream(Root[sl[i]],Stream) then begin
Result := False;
FreeAndNil(sl);
Exit;
end;
end;
FreeAndNil(s);
t := 'e';
if (Stream.Write(PChar(t)^,1) = 1) then Result := True else Result := False;
FreeAndNil(sl);
end else Result := False;
end;
function bencodeStream(Root: TObject; Stream: TStream): Boolean;
begin
if (Root is TInt64) then Result := bencodeInt64(Root as TInt64,Stream)
else if (Root is TString) then Result := bencodeString(Root as TString,Stream)
else if (Root is TStringList) then Result := bencodeStringList(Root as TStringList,Stream)
else if (Root is TObjectList) then Result := bencodeList(Root as TObjectList,Stream)
else if (Root is TObjectHash) then Result := bencodeDictionary(Root as TObjectHash,Stream)
else Result := False;
end;
function bdecodeStream(s: TStream): TObject;
var
r: TObject;
c: Char;
n: Integer;
begin
n := s.Read(c, 1);
if(n > 0) then begin
case c of
'd' : r:= bdecodeHash(s);
'l' : r:= bdecodeList(s);
'i' : r:= bdecodeInt64(s);
'0'..'9' : r:= bdecodeString(s,StrToInt(c));
else r := nil;
end;
end else begin
r := nil;
end;
bdecodeStream := r;
end;
function bdecodeHash(s: TStream): TObjectHash;
var
r: TObjectHash;
o: TObject;
n, st: Integer;
c: Char;
l: TInt64;
k: TString;
begin
r := TObjectHash.Create();
n := s.Read(c, 1);
while((n > 0) and (c <> 'e')) do begin
n := StrToInt(c);
k := bdecodeString(s, n);
if(k <> nil) then begin
st := s.Position;
o := bdecodeStream(s);
if((o <> nil) and (k.Value <> '')) then r[k.Value] := o;
if(k.Value = 'info') then begin
l := TInt64.Create(st);
r['_info_start'] := l;
l := TInt64.Create(s.Position - st);
r['_info_length'] := l;
end;
end;
n := s.Read(c, 1);
end;
bdecodeHash := r;
end;
function bdecodeList(s: TStream): TObjectList;
var
r: TObjectList;
o: TObject;
n: Integer;
c: Char;
begin
r := TObjectList.Create();
n := s.Read(c, 1);
while((n > 0) and (c <> 'e')) do begin
s.Seek(-1, soFromCurrent);
o := bdecodeStream(s);
if(o <> nil) then r.Add(o);
n := s.Read(c, 1);
end;
bdecodeList := r;
end;
function bdecodeString(s: TStream; i: Integer = 0): TString;
var
r: TString;
t: String;
c: Char;
n: Integer;
begin
c := '0';
n := s.Read(c, 1);
while((n > 0) and (c >= '0') and (c <= '9')) do begin
i := (i * 10) + StrToInt(c);
n := s.Read(c, 1);
end;
SetLength(t, i);
s.Read(PChar(t)^, i);
r := TString.Create(t);
bdecodeString := r;
end;
function bdecodeInt64(s: TStream): TInt64;
var
r: TInt64;
i: Int64;
c: Char;
n: Integer;
neg: Boolean;
begin
i := 0;
c := '0';
neg := False;
repeat
if (c = '-') then neg:= true else i := (i * 10) + StrToInt(c);
n := s.Read(c, 1);
until not ((n > 0) and (((c >= '0') and (c <= '9'))) or (c = '-'));
if neg then i := -i;
r := TInt64.Create(i);
bdecodeInt64 := r;
end;
{ TInt64 }
constructor TInt64.Create(Value: Int64);
begin
_Value := Value;
inherited Create();
end;
{ TString }
constructor TString.Create(Value: String);
begin
_Value := Value;
inherited Create();
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -