📄 unttqqwry.pas
字号:
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
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 + -