zoukankan      html  css  js  c++  java
  • 纯真IP数据库解析Delphi D10.1下正常使用

    直接一个单元,代码分享出来。

      1 unit   Net.IPLocation;
      2 
      3 interface
      4 
      5 uses System.Classes, System.SysUtils, Winapi.WinSock, Vcl.Forms,
      6   System.Math, System.SyncObjs;
      7 
      8 type
      9   TIPLocation = class(TObject)
     10   private
     11     QQWryFileName: string;
     12     QQWryFileStream: TBufferedFileStream;
     13     QQWryFileSize: Cardinal;
     14     IPRecordNum: Cardinal;
     15     FirstIPIndexOffset, LastIPIndexOffset: Cardinal;
     16     FLock: TCriticalSection;
     17 
     18     function GetQQWryFileName: string;
     19     function GetQQWryFileSize: Cardinal;
     20     function GetIPRecordNum: Cardinal;
     21     function GetQQWryDate: TDate;
     22     function GetQQWryDataFrom: string;
     23     function GetIPLocation(IPLocationOffset: Cardinal): TStringlist;
     24     function GetIPMsg(IPRecordID: Cardinal): TStringlist;
     25     function GetIPRecordID(IP: string): Cardinal;
     26     function GetIPValue(IP: string): Cardinal;
     27   public
     28     constructor Create(cQQWryFileName: string);
     29     destructor Destroy; override;
     30     function GetLocation(IP: string): String;
     31   end;
     32 
     33 function IPLocation: TIPLocation;
     34 
     35 implementation
     36 
     37 var
     38   __IPLocation: TIPLocation;
     39 
     40 function IPLocation: TIPLocation;
     41 begin
     42   if __IPLocation = nil then
     43     __IPLocation := TIPLocation.Create(ExtractFilePath(ParamStr(0)) +
     44       'qqwry.dat');
     45 
     46   Result := __IPLocation;
     47 end;
     48 
     49 { TIPLocation }
     50 
     51 constructor TIPLocation.Create(cQQWryFileName: string);
     52 begin
     53   inherited Create;
     54   FLock := TCriticalSection.Create;
     55   QQWryFileName := cQQWryFileName;
     56   QQWryFileStream := TBufferedFileStream.Create(QQWryFileName,
     57     fmOpenRead or fmShareDenyWrite, 0);
     58   QQWryFileSize := QQWryFileStream.Size;
     59   QQWryFileStream.Read(FirstIPIndexOffset, 4);
     60   QQWryFileStream.Read(LastIPIndexOffset, 4);
     61   IPRecordNum := (LastIPIndexOffset - FirstIPIndexOffset) div 7 + 1;
     62 end;
     63 
     64 destructor TIPLocation.Destroy;
     65 begin
     66 
     67   QQWryFileStream.Free;
     68   FLock.Free;
     69   inherited Destroy;
     70 end;
     71 
     72 function TIPLocation.GetIPLocation(IPLocationOffset: Cardinal): TStringlist;
     73 const
     74   // 实际信息字串存放位置的重定向模式
     75   REDIRECT_MODE_1 = 1;
     76   REDIRECT_MODE_2 = 2;
     77 var
     78   RedirectMode: byte;
     79   CountryFirstOffset, CountrySecondOffset: Cardinal;
     80   CountryMsg, AreaMsg: string;
     81   //
     82   function ReadString(StringOffset: Cardinal): ansistring;
     83   var
     84     ReadByte: ansichar;
     85   begin
     86     Result := '';
     87     QQWryFileStream.Seek(StringOffset, soFromBeginning);
     88     QQWryFileStream.Read(ReadByte, 1);
     89     while ord(ReadByte) <> 0 do
     90     begin
     91       Result := Result + ReadByte;
     92       QQWryFileStream.Read(ReadByte, 1);
     93     end;
     94   end;
     95 //
     96   function ReadArea(AreaOffset: Cardinal): ansistring;
     97   var
     98     ModeByte: byte;
     99     ReadAreaOffset: Cardinal;
    100   begin
    101     ReadAreaOffset := 0;
    102     QQWryFileStream.Seek(AreaOffset, soFromBeginning);
    103     QQWryFileStream.Read(ModeByte, 1);
    104     if (ModeByte = REDIRECT_MODE_1) or (ModeByte = REDIRECT_MODE_2) then
    105     begin
    106       QQWryFileStream.Read(ReadAreaOffset, 3);
    107       if ReadAreaOffset = 0 then
    108         Result := '未知地区'
    109       else
    110         Result := ReadString(ReadAreaOffset);
    111     end
    112     else
    113     begin
    114       Result := ReadString(AreaOffset);
    115     end;
    116   end;
    117 
    118 begin
    119   CountryFirstOffset := 0;
    120   CountrySecondOffset := 0;
    121   // 跳过4个字节,该4字节内容为该条IP信息里IP地址段中的终止IP值
    122   QQWryFileStream.Seek(IPLocationOffset + 4, soFromBeginning);
    123   // 读取国家信息的重定向模式值
    124   QQWryFileStream.Read(RedirectMode, 1);
    125   // 重定向模式1的处理
    126   if RedirectMode = REDIRECT_MODE_1 then
    127   begin
    128     // 模式值为1,则后3个字节的内容为国家信息的重定向偏移值
    129     QQWryFileStream.ReadData(CountryFirstOffset, 3);
    130     // 进行重定向
    131     QQWryFileStream.Seek(CountryFirstOffset, soFromBeginning);
    132     // 第二次读取国家信息的重定向模式
    133     QQWryFileStream.Read(RedirectMode, 1);
    134     // 第二次重定向模式为模式2的处理
    135     if RedirectMode = REDIRECT_MODE_2 then
    136     begin
    137       // 后3字节的内容即为第二次重定向偏移值
    138       QQWryFileStream.ReadData(CountrySecondOffset, 3);
    139       // 读取第二次重定向偏移值下的字符串值,即为国家信息
    140       CountryMsg := ReadString(CountrySecondOffset);
    141       // 若第一次重定向模式为1,进行重定向后读取的第二次重定向模式为2,
    142       // 则地区信息存放在第一次国家信息偏移值的后面
    143       QQWryFileStream.Seek(CountryFirstOffset + 4, soFromBeginning);
    144       // 第二次重定向模式不是模式2的处理
    145     end
    146     else
    147     begin
    148       CountryMsg := ReadString(CountryFirstOffset);
    149     end;
    150     // 在重定向模式1下读地区信息值
    151     AreaMsg := ReadArea(QQWryFileStream.Position);
    152     // 重定向模式2的处理
    153   end
    154   else if RedirectMode = REDIRECT_MODE_2 then
    155   begin
    156     QQWryFileStream.ReadData(CountrySecondOffset, 3);
    157     CountryMsg := ReadString(CountrySecondOffset);
    158     AreaMsg := ReadArea(IPLocationOffset + 8);
    159     // 不是重定向模式的处理,存放的即是IP地址信息
    160   end
    161   else
    162   begin
    163     CountryMsg := ReadString(QQWryFileStream.Position - 1);
    164     AreaMsg := ReadArea(QQWryFileStream.Position);
    165   end;
    166   Result := TStringlist.Create;
    167   Result.Add(CountryMsg);
    168   Result.Add(AreaMsg);
    169 end;
    170 
    171 function TIPLocation.GetIPMsg(IPRecordID: Cardinal): TStringlist;
    172 var
    173   aryStartIP: array [1 .. 4] of byte;
    174   strStartIP: string;
    175   EndIPOffset: Cardinal;
    176   aryEndIP: array [1 .. 4] of byte;
    177   strEndIP: string;
    178   i: integer;
    179 begin
    180   EndIPOffset := 0;
    181 
    182   // 根据记录ID号移到该记录号的索引处
    183   QQWryFileStream.Seek(FirstIPIndexOffset + (IPRecordID - 1) * 7,
    184     soFromBeginning);
    185   // 索引的前4个字节为起始IP地址
    186   QQWryFileStream.Read(aryStartIP, 4);
    187   // 后3个字节是内容区域的偏移值
    188   // QQWryFileStream.Read(EndIPOffset, 3);
    189   QQWryFileStream.ReadData(EndIPOffset, 3);
    190   // 移至内容区域
    191   QQWryFileStream.Seek(EndIPOffset, soFromBeginning);
    192   // 内容区域的前4个字节为终止IP地址
    193   QQWryFileStream.Read(aryEndIP, 4);
    194 
    195   // 将起止IP地址转换为点分的形式
    196   strStartIP := '';
    197   for i := 4 downto 1 do
    198   begin
    199     if i <> 1 then
    200       strStartIP := strStartIP + IntToStr(aryStartIP[i]) + '.'
    201     else
    202       strStartIP := strStartIP + IntToStr(aryStartIP[i]);
    203   end;
    204   strEndIP := '';
    205   for i := 4 downto 1 do
    206   begin
    207     if i <> 1 then
    208       strEndIP := strEndIP + IntToStr(aryEndIP[i]) + '.'
    209     else
    210       strEndIP := strEndIP + IntToStr(aryEndIP[i]);
    211   end;
    212   Result := TStringlist.Create;
    213   Result.Add(strStartIP);
    214   Result.Add(strEndIP);
    215   // 获取该条记录下的IP地址信息
    216   // 以下三者是统一的:①内容区域的偏移值 ②终止IP地址的存放位置 ③国家信息紧接在终止IP地址存放位置后
    217   Result.AddStrings(GetIPLocation(EndIPOffset));
    218 end;
    219 
    220 function TIPLocation.GetIPRecordID(IP: string): Cardinal;
    221   function SearchIPRecordID(IPRecordFrom, IPRecordTo, IPValue: Cardinal)
    222     : Cardinal;
    223   var
    224     CompareIPValue1, CompareIPValue2: Cardinal;
    225   begin
    226     Result := 0;
    227     CompareIPValue1 := 0;
    228     CompareIPValue2 := 0;
    229     QQWryFileStream.Seek(FirstIPIndexOffset + ((IPRecordTo - IPRecordFrom) div 2
    230       + IPRecordFrom - 1) * 7, soFromBeginning);
    231     QQWryFileStream.Read(CompareIPValue1, 4);
    232     QQWryFileStream.Seek(FirstIPIndexOffset + ((IPRecordTo - IPRecordFrom) div 2
    233       + IPRecordFrom) * 7, soFromBeginning);
    234     QQWryFileStream.Read(CompareIPValue2, 4);
    235     // 找到了
    236     if (IPValue >= CompareIPValue1) and (IPValue < CompareIPValue2) then
    237     begin
    238       Result := (IPRecordTo - IPRecordFrom) div 2 + IPRecordFrom;
    239     end
    240     else
    241       // 后半段找
    242       if IPValue > CompareIPValue1 then
    243       begin
    244         Result := SearchIPRecordID((IPRecordTo - IPRecordFrom) div 2 +
    245           IPRecordFrom + 1, IPRecordTo, IPValue);
    246       end
    247       else
    248         // 前半段找
    249         if IPValue < CompareIPValue1 then
    250         begin
    251           Result := SearchIPRecordID(IPRecordFrom, (IPRecordTo - IPRecordFrom)
    252             div 2 + IPRecordFrom - 1, IPValue);
    253         end;
    254   end;
    255 
    256 begin
    257   Result := SearchIPRecordID(1, GetIPRecordNum, GetIPValue(IP));
    258 end;
    259 
    260 function TIPLocation.GetIPRecordNum: Cardinal;
    261 begin
    262   Result := IPRecordNum;
    263 end;
    264 
    265 function TIPLocation.GetIPValue(IP: string): Cardinal;
    266 var
    267   tsIP: TStringlist;
    268   i: integer;
    269   function SplitStringToStringlist(aString: string; aSplitChar: string)
    270     : TStringlist;
    271   begin
    272     Result := TStringlist.Create;
    273     while pos(aSplitChar, aString) > 0 do
    274     begin
    275       Result.Add(copy(aString, 1, pos(aSplitChar, aString) - 1));
    276       aString := copy(aString, pos(aSplitChar, aString) + 1,
    277         length(aString) - pos(aSplitChar, aString));
    278     end;
    279     Result.Add(aString);
    280   end;
    281 
    282 begin
    283   tsIP := SplitStringToStringlist(IP, '.');
    284   Result := 0;
    285   for i := 3 downto 0 do
    286   begin
    287     Result := Result + StrToInt(tsIP[i]) * trunc(power(256, 3 - i));
    288   end;
    289 end;
    290 
    291 function TIPLocation.GetLocation(IP: string): String;
    292 begin
    293   FLock.Enter;
    294   try
    295     Result := GetIPMsg(GetIPRecordID(IP))[2];
    296   finally
    297     FLock.Leave;
    298   end;
    299 end;
    300 
    301 function TIPLocation.GetQQWryDataFrom: string;
    302 begin
    303   Result := GetIPMsg(GetIPRecordNum)[2];
    304 end;
    305 
    306 function TIPLocation.GetQQWryDate: TDate;
    307 var
    308   DateString: string;
    309 begin
    310   DateString := GetIPMsg(GetIPRecordNum)[3];
    311   DateString := copy(DateString, 1, pos('IP数据', DateString) - 1);
    312   DateString := StringReplace(DateString, '', '-',
    313     [rfReplaceAll, rfIgnoreCase]);
    314   DateString := StringReplace(DateString, '', '-',
    315     [rfReplaceAll, rfIgnoreCase]);
    316   DateString := StringReplace(DateString, '', '-',
    317     [rfReplaceAll, rfIgnoreCase]);
    318   Result := StrToDate(DateString);
    319 end;
    320 
    321 function TIPLocation.GetQQWryFileName: string;
    322 begin
    323   Result := QQWryFileName;
    324 end;
    325 
    326 function TIPLocation.GetQQWryFileSize: Cardinal;
    327 begin
    328   Result := QQWryFileSize;
    329 end;
    330 
    331 initialization
    332 
    333 finalization
    334 
    335 if __IPLocation <> nil then
    336   __IPLocation.Free;
    337 
    338 end.
  • 相关阅读:
    How to function call using 'this' inside forEach loop
    jquery.validate.unobtrusive not working with dynamic injected elements
    Difference between jQuery.extend and jQuery.fn.extend?
    Methods, Computed, and Watchers in Vue.js
    Caution using watchers for objects in Vue
    How to Watch Deep Data Structures in Vue (Arrays and Objects)
    Page: DOMContentLoaded, load, beforeunload, unload
    linux bridge
    linux bridge
    EVE-NG网卡桥接
  • 原文地址:https://www.cnblogs.com/zhunian/p/6530934.html
Copyright © 2011-2022 走看看