📄 uclass.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 + -