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

📄 uclass.cpp

📁 读取QQ IP数据库(QQWry.dat)文件格式
💻 CPP
字号:
//---------------------------------------------------------------------------


#pragma hdrstop

#include "uClass.h"
//---------------------------------------------------------------------------
// 实际信息字串存放位置的重定向模式
const REDIRECT_MODE_1 = 1;
const REDIRECT_MODE_2 = 2;
const char A_szSplitChar[] = "\r\n";
//---------------------------------------------------------------------------
// 构造一个TQQWry即QQIP地址数据库的对象
// strWryFileName: QQIP数据库文件的全名(包括路径),请确认文件存在和可读性
__fastcall TQQWry::TQQWry(String strWryFileName)
{
    FFileName = strWryFileName;
    FFileStream = new TFileStream(FFileName, fmOpenRead | fmShareDenyWrite, 0);
    FFileSize = FFileStream->Size;
    FFileStream->Seek(0, soFromBeginning);
    FFileStream->Read(&FFirstIPOffset, 4);
    FFileStream->Read(&FLastIPOffset, 4);
    FIPRecordCount = (FLastIPOffset - FFirstIPOffset) / 7 + 1;
}
//---------------------------------------------------------------------------
// 析构函数,释放TQQWry对象,释放文件数据流对象
__fastcall TQQWry::~TQQWry()
{
    delete FFileStream;
}
//---------------------------------------------------------------------------
//  获取QQIP数据库文件的全名(包括路径)
String __fastcall TQQWry::GetWryFileName()
{
    return FFileName;
}
//---------------------------------------------------------------------------
// 获取QQIP数据库文件大小
DWORD __fastcall TQQWry::GetWryFileSize()
{
    return FFileSize;
}
//---------------------------------------------------------------------------
// 获取QQIP数据库内含有的IP地址信息记录条数
DWORD __fastcall TQQWry::GetIPRecordCount()
{
    return FIPRecordCount;
}
//---------------------------------------------------------------------------
// 获取当前QQIP数据库的更新日期
String __fastcall TQQWry::GetUpdateDate()
{
    String strTemp = GetIPMsg(GetIPRecordCount());
    String strDate = strTemp.SubString(strTemp.LastDelimiter(A_szSplitChar) + 1, strTemp.Length());
    strDate = strDate.SubString(1, strDate.Pos("IP数据") - 1);
    return strDate;
}
//---------------------------------------------------------------------------
// 获取当前QQIP数据库的来源信息
String __fastcall TQQWry::GetDataFrom()
{
    String strTemp = GetIPMsg(GetIPRecordCount());
    strTemp = strTemp.SubString(strTemp.Pos(A_szSplitChar) + 2, strTemp.Length());
    strTemp = strTemp.SubString(strTemp.Pos(A_szSplitChar) + 2, strTemp.Length());
    strTemp = strTemp.SubString(1, strTemp.Pos(A_szSplitChar) - 1);
    return strTemp;
}
//---------------------------------------------------------------------------
// 给定一个文件偏移值,返回在数据文件中该偏移下的字符串,即读取到0结尾的字符前
// dwStringOffset = 字符串在文件中的偏移值
String __fastcall TQQWry::ReadString(DWORD dwStringOffset)
{
    char cReadByte = 0;
    String strRet("");
    FFileStream->Seek(dwStringOffset, soFromBeginning);
    FFileStream->Read(&cReadByte, 1);
    while(cReadByte != 0)
    {
        strRet += String(cReadByte);
        FFileStream->Read(&cReadByte, 1);
    }
    return strRet;
}
//---------------------------------------------------------------------------
// 给定一个地区信息偏移值,返回在数据文件中该偏移量下的地区信息
// dwAreaOffset = 地区信息在文件中的偏移值
// 返回地区信息字符串
String __fastcall TQQWry::ReadArea(DWORD dwAreaOffset)
{
    BYTE btMode = 0;
    DWORD dwReadAreaOffset = 0;
    FFileStream->Seek(dwAreaOffset, soFromBeginning);
    FFileStream->Read(&btMode, 1);
    if(btMode == REDIRECT_MODE_1 || btMode == REDIRECT_MODE_2)
    {
        FFileStream->Read(&dwReadAreaOffset, 3);
        if(dwAreaOffset == 0)
            return "未知地区";
        else
            return ReadString(dwReadAreaOffset);
    }
    else
        return ReadString(dwAreaOffset);
}
//---------------------------------------------------------------------------
// 给定一个IP国家地区记录的偏移,返回该IP地址的信息
// dwLocOffset = 国家记录的偏移
// 返回IP地址信息(国家信息/地区信息)
String __fastcall TQQWry::GetIPLocation(DWORD dwLocOffset)
{
    BYTE btRedirectMode = 0;
    DWORD dwCountryFirstOffset = 0, dwCountrySecondOffset = 0;
    String strCountryMsg(""), strAreaMsg("");

    // 跳过4个字节,该4字节内容为该条IP信息里IP地址段中的终止IP值
    FFileStream->Seek(dwLocOffset + 4, soFromBeginning);
    // 读取国家信息的重定向模式值
    FFileStream->Read(&btRedirectMode, 1);
    // 重定向模式1的处理
    if(btRedirectMode == REDIRECT_MODE_1)
    {
        //模式值为1,则后3个字节的内容为国家信息的重定向偏移值
        FFileStream->Read(&dwCountryFirstOffset, 3);
        // 进行重定向
        FFileStream->Seek(dwCountryFirstOffset, soFromBeginning);
        // 第二次读取国家信息的重定向模式
        FFileStream->Read(&btRedirectMode, 1);
        // 第二次重定向模式为模式2的处理
        if(btRedirectMode == REDIRECT_MODE_2)
        {
            // 后3字节的内容即为第二次重定向偏移值
            FFileStream->Read(&dwCountrySecondOffset, 3);
            // 读取第二次重定向偏移值下的字符串值,即为国家信息
            strCountryMsg = ReadString(dwCountrySecondOffset);
            // 若第一次重定向模式为1,进行重定向后读取的第二次重定向模式为2,
            // 则地区信息存放在第一次国家信息偏移值的后面
            FFileStream->Seek(dwCountryFirstOffset + 4, soFromBeginning);
            // 第二次重定向模式不是模式2的处理
        }
        else
            strCountryMsg = ReadString(dwCountryFirstOffset);
        // 在重定向模式1下读地区信息值
        strAreaMsg = ReadArea(FFileStream->Position);
    }
    // 重定向模式2的处理
    else if(btRedirectMode == REDIRECT_MODE_2)
    {
        FFileStream->Read(&dwCountrySecondOffset, 3);
        strCountryMsg = ReadString(dwCountrySecondOffset);
        strAreaMsg = ReadArea(dwLocOffset + 8);
    }
    // 不是重定向模式的处理,存放的即是IP地址信息
    else
    {
        strCountryMsg = ReadString(FFileStream->Position - 1);
        strAreaMsg = ReadArea(FFileStream->Position);
    }
    return strCountryMsg + A_szSplitChar + strAreaMsg;
}
//---------------------------------------------------------------------------
// 给定一个IP地址信息记录号,返回该项记录的信息
// dwIPRecordID = IP地址信息记录号
// 返回记录号信息, 含3个部分:①起始IP地址  ②终止IP地址  ③国家信息/地区信息
String __fastcall TQQWry::GetIPMsg(DWORD dwIPRecordID)
{
    if(dwIPRecordID == 0)
        dwIPRecordID = 1;
    if(dwIPRecordID > FIPRecordCount)
        return "记录越界";
    BYTE A_btStartIP[4], A_btEndIP[4];
    memset(&A_btStartIP, 0x00 ,4);
    memset(&A_btEndIP, 0x00 ,4);
    String strStartIP(""), strEndIP("");
    DWORD dwEndIPOffset = 0;
    // 根据记录ID号移到该记录号的索引处
    FFileStream->Seek(FFirstIPOffset + (dwIPRecordID - 1) * 7, soFromBeginning);
    // 索引的前4个字节为起始IP地址
    FFileStream->Read(&A_btStartIP, 4);
    // 后3个字节是内容区域的偏移值
    FFileStream->Read(&dwEndIPOffset, 3);
    // 移至内容区域
    FFileStream->Seek(dwEndIPOffset, soFromBeginning);
    // 内容区域的前4个字节为终止IP地址
    FFileStream->Read(&A_btEndIP, 4);

    // 将起止IP地址转换为点分的形式
    for(int i=3; i>-1; i--)
    {
        if(i != 0)
        {
            strStartIP += IntToStr(A_btStartIP[i]) + ".";
            strEndIP += IntToStr(A_btEndIP[i]) + ".";
        }
        else
        {
            strStartIP += IntToStr(A_btStartIP[i]);
            strEndIP += IntToStr(A_btEndIP[i]);
        }
    }
    return strStartIP + A_szSplitChar + strEndIP + A_szSplitChar + GetIPLocation(dwEndIPOffset);
    // 获取该条记录下的IP地址信息
    // 以下三者是统一的:
    // ①内容区域的偏移值  ②终止IP地址的存放位置 ③国家信息紧接在终止IP地址存放位置后
}
//---------------------------------------------------------------------------
//  给定一个IP地址(四段点分字符串形式),分解到TStrings中
void __fastcall SplitStringToStringList(String strSrc, String strSplitChar, TStringList *pList)
{
    while(strSrc.Pos(strSplitChar))
    {
        pList->Add(strSrc.SubString(1, strSrc.Pos(strSplitChar) - 1));
        strSrc = strSrc.SubString(strSrc.Pos(strSplitChar) + 1, strSrc.Length());
    }
    pList->Add(strSrc);
}
//---------------------------------------------------------------------------
DWORD __fastcall TQQWry::GetIPValue(String strIP)
{
    TStringList *pList = new TStringList;
    SplitStringToStringList(strIP, ".", pList);
    DWORD dwRet = 0;
    for(int i=3; i>-1; i--)
        dwRet += pList->Strings[i].ToInt() * (pow(256, 3-i));
    delete pList;
    return dwRet;
}
//---------------------------------------------------------------------------
// 给定一个IP地址(四段点分字符串形式),返回该IP地址所在的记录号
DWORD __fastcall TQQWry::SearchIPRecordID(DWORD dwIPRecordFrom,
        DWORD dwIPRecordTo, DWORD dwIPValue)
{
    DWORD dwCompareIPValue1 = 0, dwCompareIPValue2 = 0;
    FFileStream->Seek(FFirstIPOffset + ((dwIPRecordTo - dwIPRecordFrom) / 2
            + dwIPRecordFrom - 1) * 7, soFromBeginning);
    FFileStream->Read(&dwCompareIPValue1, 4);
    FFileStream->Seek(FFirstIPOffset + ((dwIPRecordTo - dwIPRecordFrom) / 2
            + dwIPRecordFrom) * 7, soFromBeginning);
    FFileStream->Read(&dwCompareIPValue2, 4);
    // 找到了
    if(dwIPValue >= dwCompareIPValue1 && dwIPValue < dwCompareIPValue2)
        return (dwIPRecordTo - dwIPRecordFrom) / 2 + dwIPRecordFrom;
    else
    {
        // 后半段找
        if(dwIPValue > dwCompareIPValue1)
            return SearchIPRecordID((dwIPRecordTo - dwIPRecordFrom) / 2
                    + dwIPRecordFrom + 1, dwIPRecordTo, dwIPValue);
        // 前半段找
        else
        {
            if(dwIPValue < dwCompareIPValue1)
                return SearchIPRecordID(dwIPRecordFrom,
                        (dwIPRecordTo - dwIPRecordFrom) / 2
                        + dwIPRecordFrom - 1, dwIPValue);
        }
    }
    return 0;
}
//---------------------------------------------------------------------------
DWORD __fastcall TQQWry::GetIPRecordID(String strIP)
{
    if(strIP.Length() < 7 || strIP.Length() > 15)
        return 1;
    if(INADDR_NONE == inet_addr(strIP.c_str()))
        return 1;
    return SearchIPRecordID(1, GetIPRecordCount(), GetIPValue(strIP));
}

//---------------------------------------------------------------------------
bool CompactMDB(String strMdbFileName, String strPass1, String strPass2)
{
    bool bReturn;
    String strFileTemp = ChangeFileExt(strMdbFileName, ".Tmp");
    String strProvider1 = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" +
            strMdbFileName + ";Jet OLEDB:Database Password=" + strPass1;
    String strProvider2 = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" +
            strFileTemp + ";Jet OLEDB:Database Password=" + strPass2;

    Variant AdoObj;
    try
    {
        if(FileExists(strFileTemp))
            DeleteFile(strFileTemp);
        AdoObj = Variant::CreateObject("JRO.JetEngine");
        AdoObj.OleProcedure("CompactDatabase",
                WideString(strProvider1), WideString(strProvider2));
        if(FileExists(strMdbFileName))
            DeleteFile(strMdbFileName);
        RenameFile(strFileTemp,strMdbFileName);
        bReturn = true;
    }
    catch(...)
    {
        bReturn = false;
    }
    AdoObj.Clear();
    return bReturn;
}
#pragma package(smart_init)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -