⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 unttqqwry.pas

📁 原版翎风(LF)引擎(M2)源码(Delphi)
💻 PAS
📖 第 1 页 / 共 2 页
字号:
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 + -