?? unttqqwry.pas
字號:
procedure TQQWry.GetIPLocationByEndIPOffset(EndIPOffset: int64; var IPLocation: PChar);
const
//實際信息字串存放位置的重定向模式
REDIRECT_MODE_1 = 1;
REDIRECT_MODE_2 = 2;
var
RedirectMode: byte;
pSplit: PChar;
CountryFirstOffset, CountrySecondOffset: int64;
IPCountryLen: integer;
IPArea: PChar;
///**
//* 給定一個地區信息偏移值,返回在數據文件中該偏移量下的地區信息
//* @param (AreaOffset, IPArea) (地區信息在文件中的偏移值, 返回的地區信息)
//* @return
//*/
procedure ReadIPAreaByAreaOffset(AreaOffset: int64; var IPArea: PChar);
var
ModeByte: byte;
ReadAreaOffset: int64;
begin
try
ModeByte:=0;
ReadAreaOffset:=0;
//取內存文件映射首地址
pQQWryPos:=pQQWryMapFile;
//移到偏移處
inc(pQQWryPos, AreaOffset);
//讀模式
CopyMemory(@ModeByte, pQQWryPos, 1);
//模式1或2,后3字節為偏移
if (ModeByte = REDIRECT_MODE_1) or (ModeByte = REDIRECT_MODE_2) then begin
//讀偏移
Inc(pQQWryPos);
CopyMemory(@ReadAreaOffset, pQQWryPos, 3);
//若偏移為0,則為未知地區,對于以前的數據庫有這個錯誤
if ReadAreaOffset=0 then IPArea:='未知地區'
else begin //去偏移處讀字符串
pQQWryPos:=pQQWryMapFile;
Inc(pQQWryPos, ReadAreaOffset);
CopyMemory(IPArea, PChar(pQQWryPos), StrLen(PChar(pQQWryPos)));
end;
//沒有模式,直接讀字符串
end else begin
pQQWryPos:=pQQWryMapFile;
Inc(pQQWryPos, AreaOffset);
CopyMemory(IPArea, PChar(pQQWryPos), StrLen(PChar(pQQWryPos)));
end;
except
on E: Exception do begin
raise Exception.Create(E.Message);
exit;
end;
end;
end;
begin
try
RedirectMode:=0;
pSplit:=' ';
CountryFirstOffset:=0;
CountrySecondOffset:=0;
//取內存文件映射首地址
pQQWryPos:=pQQWryMapFile;
//根據記錄ID號移到該記錄號的索引處
Inc(pQQWryPos, EndIPOffset + 4);
CopyMemory(@RedirectMode, pQQWryPos, 1);
//重定向模式1的處理
if RedirectMode = REDIRECT_MODE_1 then begin
Inc(pQQWryPos);
//模式值為1,則后3個字節的內容為國家信息的偏移值
CopyMemory(@CountryFirstOffset, pQQWryPos, 3);
//進行重定向
pQQWryPos:=pQQWryMapFile;
Inc(pQQWryPos, CountryFirstOffset);
//第二次讀取國家信息的重定向模式
CopyMemory(@RedirectMode, pQQWryPos, 1);
//第二次重定向模式為模式2的處理
if RedirectMode = REDIRECT_MODE_2 then begin
//后3字節的內容即為第二次重定向偏移值
Inc(pQQWryPos);
CopyMemory(@CountrySecondOffset, pQQWryPos, 3);
//讀取第二次重定向偏移值下的字符串值,即為國家信息
pQQWryPos:=pQQWryMapFile;
Inc(pQQWryPos, CountrySecondOffset);
IPCountryLen:=StrLen(PChar(pQQWryPos));
CopyMemory(IPLocation, PChar(pQQWryPos), IPCountryLen);
//用空格分割國家和地區
CopyMemory(@IPLocation[IPCountryLen], pSplit, 1);
//若第一次重定向模式為1,進行重定向后讀取的第二次重定向模式為2,
//則地區信息存放在第一次國家信息偏移值的后面
IPArea:=PChar(@IPLocation[IPCountryLen + 1]);
ReadIPAreaByAreaOffset(CountryFirstOffset + 4, IPArea);
//第二次重定向模式不是模式2的處理
end else begin
IPCountryLen:=StrLen(PChar(pQQWryPos));
CopyMemory(IPLocation, PChar(pQQWryPos), IPCountryLen);
//用空格分割國家和地區
CopyMemory(@IPLocation[IPCountryLen], pSplit, 1);
//讀地區信息
IPArea:=PChar(@IPLocation[IPCountryLen + 1]);
ReadIPAreaByAreaOffset(CountryFirstOffset + IPCountryLen + 1, IPArea);
end;
//重定向模式2的處理
end else if RedirectMode = REDIRECT_MODE_2 then begin
Inc(pQQWryPos);
//模式值為2,則后3個字節的內容為國家信息的偏移值
CopyMemory(@CountrySecondOffset, pQQWryPos, 3);
//進行重定向
pQQWryPos:=pQQWryMapFile;
Inc(pQQWryPos, CountrySecondOffset);
//國家信息
IPCountryLen:=StrLen(PChar(pQQWryPos));
CopyMemory(IPLocation, PChar(pQQWryPos), IPCountryLen);
//用空格分割國家和地區
CopyMemory(@IPLocation[IPCountryLen], pSplit, 1);
//地區信息
IPArea:=PChar(@IPLocation[IPCountryLen + 1]);
ReadIPAreaByAreaOffset(EndIPOffset + 8, IPArea);
//不是重定向模式的處理,存放的即是IP地址信息
end else begin
//國家信息
IPCountryLen:=StrLen(PChar(pQQWryPos));
CopyMemory(IPLocation, PChar(pQQWryPos), IPCountryLen);
//用空格分割國家和地區
CopyMemory(@IPLocation[IPCountryLen], pSplit, 1);
//地區信息
IPArea:=PChar(@IPLocation[IPCountryLen + 1]);
ReadIPAreaByAreaOffset(EndIPOffset + 4 + IPCountryLen + 1, IPArea);
end;
except
on E: Exception do begin
raise Exception.Create(E.Message);
exit;
end;
end;
end;
///**
//* 給定一個IP地址信息記錄號,返回該項記錄的信息,用Stringlist接收該條信息,效率較低
//* @param (IPRecordID, IPData) (IP地址信息記錄號, 返回的該條信息:①起始IP ②結束IP ③國家 ④地區)
//* @return 無
//*/
procedure TQQWry.GetIPDataByIPRecordID(IPRecordID: int64; var IPData: TStringlist);
var
aryIPData: array[0..254] of char;
pIPData: PChar;
i: integer;
begin
try
FillChar(aryIPData, SizeOf(aryIPData), #0);
pIPData:=PChar(@aryIPData[0]);
GetIPDataByIPRecordID(IPRecordID, pIPData);
//去掉結尾的回車符
pIPData[StrLen(pIPData) - 2]:=#0;
IPData.CommaText:=StrPas(pIPData);
//有可能地區為空,也有可能地區中含有空格
for i:=1 to 4 - IPData.Count do
IPData.Add('無');
for i:=5 to IPData.Count do
IPData[3]:=IPData[3] + ' ' + IPData[i - 1];
except
on E: Exception do begin
raise Exception.Create(E.Message);
exit;
end;
end;
end;
///**
//* 給定一個IP地址(四段點分字符串形式),返回該IP的數值
//* @param (IP) (IP地址,四段點分字符串形式)
//* @return 該IP的數值
//*/
function TQQWry.GetIPValue(IP: string): int64;
var
slIP: TStringlist;
i: integer;
function SplitStringToStringlist(aString: string; aSplitChar: string): TStringlist;
begin
Result:=TStringList.Create;
while pos(aSplitChar, aString)>0 do begin
Result.Add(copy(aString, 1, pos(aSplitChar, aString)-1));
aString:=copy(aString, pos(aSplitChar, aString)+1, length(aString)-pos(aSplitChar, aString));
end;
Result.Add(aString);
end;
begin
try
slIP:=SplitStringToStringlist(IP, '.');
Result:=0;
for i:=3 downto 0 do begin
Result:=Result + StrToInt(slIP[i]) * trunc(power(256, 3-i));
end;
except
on E: Exception do begin
raise Exception.Create('無效的IP地址!');
exit;
end;
end;
end;
///**
//* 給定一個IP地址(四段點分字符串形式),返回該IP地址所在的記錄號
//* @param IP IP地址(四段點分字符串形式) string
//* @return 該IP地址所在的記錄號 Cardinal
//*/
function TQQWry.GetIPDataID(IP: string): int64;
function SearchIPDataID(IPRecordFrom, IPRecordTo, IPValue: int64): int64;
var
CompareIPValue1, CompareIPValue2: int64;
begin
Result:=0;
CompareIPValue1:=0;
CompareIPValue2:=0;
pQQWryPos:=pQQWryMapFile;
Inc(pQQWryPos, FirstIPIndexOffset + ((IPRecordTo - IPRecordFrom) div 2 + IPRecordFrom - 1) * 7);
CopyMemory(@CompareIPValue1, pQQWryPos, 4);
pQQWryPos:=pQQWryMapFile;
Inc(pQQWryPos, FirstIPIndexOffset + ((IPRecordTo - IPRecordFrom) div 2 + IPRecordFrom) * 7);
CopyMemory(@CompareIPValue2, pQQWryPos, 4);
//找到了
if (IPRecordFrom=IPRecordTo) or ((IPValue>=CompareIPValue1) and (IPValue<CompareIPValue2)) then begin
Result:=(IPRecordTo - IPRecordFrom) div 2 + IPRecordFrom;
end else
//后半段找
if IPValue>CompareIPValue1 then begin
Result:=SearchIPDataID((IPRecordTo - IPRecordFrom) div 2 + IPRecordFrom + 1, IPRecordTo, IPValue);
end else
//前半段找
if IPValue<CompareIPValue1 then begin
Result:=SearchIPDataID(IPRecordFrom, (IPRecordTo - IPRecordFrom) div 2 + IPRecordFrom - 1, IPValue);
end;
end;
begin
try
Result:=SearchIPDataID(1, GetIPDataNum, GetIPValue(IP));
except
on E: Exception do begin
Destroy;
raise Exception.Create(E.Message);
exit;
end;
end;
end;
///**
//* 將IP地址數據庫解壓成文本文件
//* @param (ATxtFileName) (解壓后的文本文件全名)
//* @return -1為解壓失敗,非-1值為解壓所耗時間,單位毫秒
//*/
function TQQWry.ExtractIPDataToTxtFile(ATxtFileName: string): integer;
var
QQWryMemoryStream: TMemoryStream;
i: integer;
IPData, NowPos: PChar;
TimeCounter: DWORD;
pReturn: PChar;
begin
result:=-1;
try
IPData:=StrAlloc(41943040);
NowPos:=IPData;
TimeCounter:=GetTickCount;
for i:=1 to GetIPDataNum do begin
GetIPDataByIPRecordID(i, NowPos);
Inc(NowPos, StrLen(NowPos));
end;
pReturn:=#13#10;
NowPos:=StrECopy(NowPos, pReturn);
NowPos:=StrECopy(NowPos, pReturn);
NowPos:=StrECopy(NowPos, PChar(format('IP數據庫共有數據 : %d 條', [GetIPDataNum])));
NowPos:=StrECopy(NowPos, pReturn);
QQWryMemoryStream:=TMemoryStream.Create;
QQWryMemoryStream.SetSize(NowPos - IPData);
QQWryMemoryStream.WriteBuffer(IPData^, NowPos - IPData);
QQWryMemoryStream.SaveToFile(ATxtFileName);
StrDispose(IPData);
QQWryMemoryStream.Destroy;
result:=GetTickCount-TimeCounter;
except
on E: Exception do begin
raise Exception.Create(E.Message);
exit;
end;
end;
end;
end.
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -