📄 idipaddress.pas
字号:
{ $HDR$}
{**********************************************************************}
{ Unit archived using Team Coherence }
{ Team Coherence is Copyright 2002 by Quality Software Components }
{ }
{ For further information / comments, visit our WEB site at }
{ http://www.TeamCoherence.com }
{**********************************************************************}
{}
{ $Log: 52330: IdIPAddress.pas
{
{ Rev 1.9 28.09.2004 20:54:32 Andreas Hausladen
{ Removed unused functions that were moved to IdGlobal
}
{
Rev 1.8 6/11/2004 8:48:20 AM DSiders
Added "Do not Localize" comments.
}
{
Rev 1.7 5/19/2004 10:44:34 PM DSiders
Corrected spelling for TIdIPAddress.MakeAddressObject method.
}
{
{ Rev 1.6 14/04/2004 17:35:38 HHariri
{ Removed IP6 for BCB temporarily
}
{
{ Rev 1.5 2/11/2004 5:10:40 AM JPMugaas
{ Moved IPv6 address definition to System package.
}
{
{ Rev 1.4 2004.02.03 4:17:18 PM czhower
{ For unit name changes.
}
{
{ Rev 1.3 2/2/2004 12:22:24 PM JPMugaas
{ Now uses IdGlobal IPVersion Type. Added HToNBytes for things that need
{ to export into NetworkOrder for structures used in protocols.
}
{
{ Rev 1.2 1/3/2004 2:13:56 PM JPMugaas
{ Removed some empty function code that wasn't used.
{ Added some value comparison functions.
{ Added a function in the IPAddress object for comparing the value with another
{ IP address. Note that this comparison is useful as an IP address will take
{ several forms (especially common with IPv6).
{ Added a property for returning the IP address as a string which works for
{ both IPv4 and IPv6 addresses.
}
{
{ Rev 1.1 1/3/2004 1:03:14 PM JPMugaas
{ Removed Lo as it was not needed and is not safe in NET.
}
{
{ Rev 1.0 1/1/2004 4:00:18 PM JPMugaas
{ An object for handling both IPv4 and IPv6 addresses. This is a proposal with
{ some old code for conversions.
}
unit IdIPAddress;
interface
uses
Classes,
IdGlobal;
type
TIdIPAddress = class(TObject)
protected
FIPv4 : Cardinal;
FIPv6 : TIdIPv6Address;
FAddrType : TIdIPVersion;
class function IPv4MakeCardInRange(const AInt : Int64; const A256Power : Integer) : Cardinal;
//general conversion stuff
class function IPv6ToIdIPv6Address(const AIPAddress : String; var VErr : Boolean) : TIdIPv6Address;
class function IPv4ToCardinal(const AIPAddress : String; var VErr : Boolean) : Cardinal;
class function MakeCanonicalIPv6Address(const AAddr: string): string;
class function MakeCanonicalIPv4Address(const AAddr: string): string;
//property as String Get methods
function GetIPv4AsString : String;
function GetIPv6AsString : String;
function GetIPAddress : String;
public
function GetHToNBytes: TIdBytes;
public
constructor Create; virtual;
class function MakeAddressObject(const AIP : String) : TIdIPAddress;
function CompareAddress(const AIP : String; var Err : Boolean) : Integer;
property IPv4 : Cardinal read FIPv4 write FIPv4;
property IPv4AsString : String read GetIPv4AsString;
{$IFNDEF BCB}
property IPv6 : TIdIPv6Address read FIPv6 write FIPv6;
{$ENDIF}
property IPv6AsString : String read GetIPv6AsString;
property AddrType : TIdIPVersion read FAddrType write FAddrType;
property IPAsString : String read GetIPAddress;
property HToNBytes : TIdBytes read GetHToNBytes;
end;
implementation
uses SysUtils, IdStack;
//The power constants are for processing IP addresses
//They are powers of 255.
const POWER_1 = $000000FF;
POWER_2 = $0000FFFF;
POWER_3 = $00FFFFFF;
POWER_4 = $FFFFFFFF;
//IPv4 address conversion
//Much of this is based on http://www.pc-help.org/obscure.htm
function OctalToInt64(const AValue: string): Int64;
//swiped from:
//http://www.swissdelphicenter.ch/torry/showcode.php?id=711
var
i: Integer;
begin
Result := 0;
for i := 1 to Length(AValue) do
begin
Result := Result * 8 + StrToInt(Copy(AValue, i, 1));
end;
end;
function CompareWord(const AWord1, AWord2 : Word) : Integer;
{
AWord1 > AWord2 > 0
AWord1 < AWord2 < 0
AWord1 = AWord2 = 0
}
begin
Result := 0;
if AWord1 > AWord2 then
begin
Result := 1;
end
else
begin
if AWord1 < AWord2 then
begin
Result := -1;
end;
end;
end;
function CompareCardinal(const ACard1, ACard2 : Cardinal) : Integer;
{
ACard1 > ACard2 > 0
ACard1 < ACard2 < 0
ACard1 = ACard2 = 0
}
begin
Result := 0;
if ACard1 > ACard2 then
begin
Result := 1;
end
else
begin
if ACard1 < ACard2 then
begin
Result := -1;
end;
end;
end;
{ TIdIPAddress }
function TIdIPAddress.CompareAddress(const AIP: String;
var Err: Boolean): Integer;
var LIP2 : TIdIPAddress;
i : Integer;
{
Note that the IP address in the object is S1.
S1 > S2 > 0
S1 < S2 < 0
S1 = S2 = 0
}
begin
Result := 0;
//LIP2 may be nil if the IP address is invalid
LIP2 := MakeAddressObject(AIP);
Err := not Assigned(LIP2);
if not Err then
begin
try
//we can't compare an IPv4 address with an IPv6 address
Err := FAddrType <> LIP2.FAddrType;
if not Err then
begin
if FAddrType = Id_IPv4 then
begin
Result := CompareCardinal(FIPv4,LIP2.FIPv4);
end
else
begin
for i := 0 to 7 do
begin
Result := CompareWord(FIPv6[i],LIP2.FIPv6[i]);
if Result <> 0 then
begin
Break;
end;
end;
end;
end;
finally
FreeAndNil(LIP2);
end;
end;
end;
constructor TIdIPAddress.Create;
begin
inherited Create;
FAddrType := Id_IPv4;
FIPv4 := 0; //'0.0.0.0'
end;
function TIdIPAddress.GetHToNBytes: TIdBytes;
var
i : Integer;
begin
SetLength(Result,0);
case Self.FAddrType of
Id_IPv4 :
begin
Result := ToBytes( GStack.HostToNetwork( FIPv4));
end;
Id_IPv6 :
begin
for i := 0 to 7 do begin
AppendBytes(Result, ToBytes(GStack.HostToNetwork(FIPv6[i]) ) );
end;
end;
end;
end;
function TIdIPAddress.GetIPAddress: String;
begin
if FAddrType = Id_IPv4 then
begin
Result := GetIPv4AsString;
end
else
begin
Result := GetIPv6AsString;
end;
end;
function TIdIPAddress.GetIPv4AsString: String;
begin
Result := '';
if FAddrType = Id_IPv4 then
begin
Result := IntToStr((FIPv4 shr 24) and $FF)+'.';
Result := Result + IntToStr((FIPv4 shr 16) and $FF)+'.';
Result := Result + IntToStr((FIPv4 shr 8) and $FF)+'.';
Result := Result + IntToStr(FIPv4 and $FF);
end;
end;
function TIdIPAddress.GetIPv6AsString: String;
var i:integer;
begin
Result := '';
if FAddrType = Id_IPv6 then
begin
Result := IntToHex(FIPv6[0], 4);
for i := 1 to 7 do begin
Result := Result + ':' + IntToHex(FIPv6[i], 4);
end;
end;
end;
class function TIdIPAddress.IPv4MakeCardInRange(const AInt: Int64;
const A256Power: Integer): Cardinal;
begin
case A256Power of
4 : Result := (AInt and POWER_4);
3 : Result := (AInt and POWER_3);
2 : Result := (AInt and POWER_2);
else
Result := (AInt and POWER_1);
end;
end;
class function TIdIPAddress.IPv4ToCardinal(const AIPAddress: String;
var VErr: Boolean): Cardinal;
var
LBuf, LBuf2 : String;
L256Power : Integer;
LParts : Integer; //how many parts should we process at a time
begin
// S.G. 11/8/2003: Added overflow checking disabling and change multiplys by SHLs.
// Locally disable overflow checking so we can safely use SHL and SHR
{$ifopt Q+} // detect previous setting
{$define _QPlusWasEnabled}
{$Q-}
{$endif}
VErr := True;
L256Power := 4;
LBuf2 := AIPAddress;
Result := 0;
repeat
LBuf := Fetch(LBuf2,'.');
if LBuf = '' then
begin
break;
end;
//We do things this way because we have to treat
//IP address parts differently than a whole number
//and sometimes, there can be missing periods.
if (LBuf2='') and (L256Power > 1) then
begin
LParts := L256Power;
Result := Result shl (L256Power SHL 3);
end
else
begin
LParts := 1;
result := result SHL 8;
end;
if (Copy(LBuf,1,2)=HEXPREFIX) then
begin
//this is a hexideciaml number
if IsHexidecimal(Copy(LBuf,3,MaxInt))=False then
begin
Exit;
end
else
begin
Result := Result + IPv4MakeCardInRange(StrToInt64Def(LBuf,0), LParts);
end;
end
else
begin
if IsNumeric(LBuf) then
begin
if (LBuf[1]='0') and IsOctal(LBuf) then
begin
//this is octal
Result := Result + IPv4MakeCardInRange(OctalToInt64(LBuf),LParts);
end
else
begin
//this must be a decimal
Result := Result + IPv4MakeCardInRange(StrToInt64Def(LBuf,0), LParts);
end;
end
else
begin
//There was an error meaning an invalid IP address
Exit;
end;
end;
Dec(L256Power);
until False;
VErr := False;
// Restore overflow checking
{$ifdef _QPlusWasEnabled} // detect previous setting
{$undef _QPlusWasEnabled}
{$Q-}
{$endif}
end;
class function TIdIPAddress.IPv6ToIdIPv6Address(const AIPAddress: String;
var VErr: Boolean): TIdIPv6Address;
var
LAddress:string;
i:integer;
begin
LAddress := MakeCanonicalIPv6Address(AIPAddress);
VErr := (LAddress='');
if not VErr then begin
for i := 0 to 7 do begin
Result[i]:=StrToInt('$'+fetch(LAddress,':'));
end;
end;
end;
class function TIdIPAddress.MakeAddressObject(
const AIP: String): TIdIPAddress;
var LErr : Boolean;
begin
Result := TIdIPAddress.Create;
Result.FIPv6 := Result.IPv6ToIdIPv6Address(AIP,LErr);
if LErr then
begin
Result.FIPv4 := Result.IPv4ToCardinal(AIP,LErr);
if LErr then
begin
//this is not a valid IPv4 address
FreeAndNil(Result);
end
else
begin
Result.FAddrType := Id_IPv4;
end;
end
else
begin
Result.FAddrType := Id_IPv6;
end;
end;
class function TIdIPAddress.MakeCanonicalIPv4Address(
const AAddr: string): string;
var LErr : Boolean;
LIP : Cardinal;
begin
LIP := IPv4ToDWord(AAddr,LErr);
if LErr then
begin
Result := '';
end
else
begin
Result := MakeDWordIntoIPv4Address(LIP);
end;
end;
class function TIdIPAddress.MakeCanonicalIPv6Address(
const AAddr: string): string;
// return an empty string if the address is invalid,
// for easy checking if its an address or not.
var
p, i: integer;
dots, colons: integer;
colonpos: array[1..8] of integer;
dotpos: array[1..3] of integer;
LAddr: string;
num: integer;
haddoublecolon: boolean;
fillzeros: integer;
begin
Result := ''; // error
LAddr := AAddr;
if Length(LAddr) = 0 then exit;
if LAddr[1] = ':' then begin
LAddr := '0'+LAddr;
end;
if LAddr[Length(LAddr)] = ':' then begin
LAddr := LAddr + '0';
end;
dots := 0;
colons := 0;
for p := 1 to Length(LAddr) do begin
case LAddr[p] of
'.' : begin
inc(dots);
if dots < 4 then begin
dotpos[dots] := p;
end else begin
exit; // error in address
end;
end;
':' : begin
inc(colons);
if colons < 8 then begin
colonpos[colons] := p;
end else begin
exit; // error in address
end;
end;
'a'..'f',
'A'..'F': if dots>0 then exit;
// allow only decimal stuff within dotted portion, ignore otherwise
'0'..'9': ; // do nothing
else exit; // error in address
end; // case
end; // for
if not (dots in [0,3]) then begin
exit; // you have to write 0 or 3 dots...
end;
if dots = 3 then begin
if not (colons in [2..6]) then begin
exit; // must not have 7 colons if we have dots
end;
if colonpos[colons] > dotpos[1] then begin
exit; // x:x:x.x:x:x is not valid
end;
end else begin
if not (colons in [2..7]) then begin
exit; // must at least have two colons
end;
end;
// now start :-)
num := StrToIntDef('$'+Copy(LAddr, 1, colonpos[1]-1), -1);
if (num<0) or (num>65535) then begin
exit; // huh? odd number...
end;
Result := IntToHex(num,1)+':';
haddoublecolon := false;
for p := 2 to colons do begin
if colonpos[p-1] = colonpos[p]-1 then begin
if haddoublecolon then begin
Result := '';
exit; // only a single double-dot allowed!
end;
haddoublecolon := true;
fillzeros := 8 - colons;
if dots>0 then dec(fillzeros,2);
for i := 1 to fillzeros do begin
Result := Result + '0:'; {do not localize}
end;
end else begin
num := StrToIntDef('$'+Copy(LAddr, colonpos[p-1]+1, colonpos[p]-colonpos[p-1]-1), -1);
if (num<0) or (num>65535) then begin
Result := '';
exit; // huh? odd number...
end;
Result := Result + IntToHex(num,1)+':';
end;
end; // end of colon separated part
if dots = 0 then begin
num := StrToIntDef('$'+Copy(LAddr, colonpos[colons]+1, MaxInt), -1);
if (num<0) or (num>65535) then begin
Result := '';
exit; // huh? odd number...
end;
Result := Result + IntToHex(num,1)+':';
end;
if dots > 0 then begin
num := StrToIntDef(Copy(LAddr, colonpos[colons]+1, dotpos[1]-colonpos[colons]-1),-1);
if (num < 0) or (num>255) then begin
Result := '';
exit;
end;
Result := Result + IntToHex(num, 2);
num := StrToIntDef(Copy(LAddr, dotpos[1]+1, dotpos[2]-dotpos[1]-1),-1);
if (num < 0) or (num>255) then begin
Result := '';
exit;
end;
Result := Result + IntToHex(num, 2)+':';
num := StrToIntDef(Copy(LAddr, dotpos[2]+1, dotpos[3]-dotpos[2]-1),-1);
if (num < 0) or (num>255) then begin
Result := '';
exit;
end;
Result := Result + IntToHex(num, 2);
num := StrToIntDef(Copy(LAddr, dotpos[3]+1, 3), -1);
if (num < 0) or (num>255) then begin
Result := '';
exit;
end;
Result := Result + IntToHex(num, 2)+':';
end;
SetLength(Result, Length(Result)-1);
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -