您的位置:首页 > 编程语言 > Delphi

纯真IP数据库解析Delphi D10.1下正常使用

2017-11-23 00:00 337 查看

纯真IP数据库解析Delphi D10.1下正常使用

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

Delphi/Pascal

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

285

286

287

288

289

290

291

292

293

294

295

296

297

298

299

300

301

302

303

304

305

306

307

308

309

310

311

312

313

314

315

316

317

318

319

320

321

322

323

324

325

326

327

328

329

330

331

332

333

334

335

336

337

338

unit

Net.IPLocation;

interface

uses
System.Classes,
System.SysUtils,
Winapi.WinSock,
Vcl.Forms,

System.Math,
System.SyncObjs;

type

TIPLocation
=
class(TObject)

private

QQWryFileName:
string;

QQWryFileStream:
TBufferedFileStream;

QQWryFileSize:
Cardinal;

IPRecordNum:
Cardinal;

FirstIPIndexOffset,
LastIPIndexOffset:
Cardinal;

FLock:
TCriticalSection;

function
GetQQWryFileName:
string;

function
GetQQWryFileSize:
Cardinal;

function
GetIPRecordNum:
Cardinal;

function
GetQQWryDate:
TDate;

function
GetQQWryDataFrom:
string;

function
GetIPLocation(IPLocationOffset:
Cardinal):
TStringlist;

function
GetIPMsg(IPRecordID:
Cardinal):
TStringlist;

function
GetIPRecordID(IP:
string):
Cardinal;

function
GetIPValue(IP:
string):
Cardinal;

public

constructor
Create(cQQWryFileName:
string);

destructor
Destroy;
override;

function
GetLocation(IP:
string):
String;

end;

function
IPLocation:
TIPLocation;

implementation

var

__IPLocation:
TIPLocation;

function
IPLocation:
TIPLocation;

begin

if
__IPLocation
=
nil
then

__IPLocation
:=
TIPLocation.Create(ExtractFilePath(ParamStr(0))
+

'qqwry.dat');

Result
:=
__IPLocation;

end;

{
TIPLocation
}

constructor
TIPLocation.Create(cQQWryFileName:
string);

begin

inherited
Create;

FLock
:=
TCriticalSection.Create;

QQWryFileName
:=
cQQWryFileName;

QQWryFileStream
:=
TBufferedFileStream.Create(QQWryFileName,

fmOpenRead
or
fmShareDenyWrite,
0);

QQWryFileSize
:=
QQWryFileStream.Size;

QQWryFileStream.Read(FirstIPIndexOffset,
4);

QQWryFileStream.Read(LastIPIndexOffset,
4);

IPRecordNum
:=
(LastIPIndexOffset
-
FirstIPIndexOffset)
div
7
+
1;

end;

destructor
TIPLocation.Destroy;

begin

QQWryFileStream.Free;

FLock.Free;

inherited
Destroy;

end;

function
TIPLocation.GetIPLocation(IPLocationOffset:
Cardinal):
TStringlist;

const

//
实际信息字串存放位置的重定向模式

REDIRECT_MODE_1
=
1;

REDIRECT_MODE_2
=
2;

var

RedirectMode:
byte;

CountryFirstOffset,
CountrySecondOffset:
Cardinal;

CountryMsg,
AreaMsg:
string;

//

function
ReadString(StringOffset:
Cardinal):
ansistring;

var

ReadByte:
ansichar;

begin

Result
:=
'';

QQWryFileStream.Seek(StringOffset,
soFromBeginning);

QQWryFileStream.Read(ReadByte,
1);

while
ord(ReadByte)
<>
0
do

begin

Result
:=
Result
+
ReadByte;

QQWryFileStream.Read(ReadByte,
1);

end;

end;

//

function
ReadArea(AreaOffset:
Cardinal):
ansistring;

var

ModeByte:
byte;

ReadAreaOffset:
Cardinal;

begin

ReadAreaOffset
:=
0;

QQWryFileStream.Seek(AreaOffset,
soFromBeginning);

QQWryFileStream.Read(ModeByte,
1);

if
(ModeByte
=
REDIRECT_MODE_1)
or
(ModeByte
=
REDIRECT_MODE_2)
then

begin

QQWryFileStream.Read(ReadAreaOffset,
3);

if
ReadAreaOffset
=
0
then

Result
:=
'未知地区'

else

Result
:=
ReadString(ReadAreaOffset);

end

else

begin

Result
:=
ReadString(AreaOffset);

end;

end;

begin

CountryFirstOffset
:=
0;

CountrySecondOffset
:=
0;

//
跳过4个字节,该4字节内容为该条IP信息里IP地址段中的终止IP值

QQWryFileStream.Seek(IPLocationOffset
+
4,
soFromBeginning);

//
读取国家信息的重定向模式值

QQWryFileStream.Read(RedirectMode,
1);

//
重定向模式1的处理

if
RedirectMode
=
REDIRECT_MODE_1
then

begin

//
模式值为1,则后3个字节的内容为国家信息的重定向偏移值

QQWryFileStream.ReadData(CountryFirstOffset,
3);

//
进行重定向

QQWryFileStream.Seek(CountryFirstOffset,
soFromBeginning);

//
第二次读取国家信息的重定向模式

QQWryFileStream.Read(RedirectMode,
1);

//
第二次重定向模式为模式2的处理

if
RedirectMode
=
REDIRECT_MODE_2
then

begin

//
后3字节的内容即为第二次重定向偏移值

QQWryFileStream.ReadData(CountrySecondOffset,
3);

//
读取第二次重定向偏移值下的字符串值,即为国家信息

CountryMsg
:=
ReadString(CountrySecondOffset);

//
若第一次重定向模式为1,进行重定向后读取的第二次重定向模式为2,

//
则地区信息存放在第一次国家信息偏移值的后面

QQWryFileStream.Seek(CountryFirstOffset
+
4,
soFromBeginning);

//
第二次重定向模式不是模式2的处理

end

else

begin

CountryMsg
:=
ReadString(CountryFirstOffset);

end;

//
在重定向模式1下读地区信息值

AreaMsg
:=
ReadArea(QQWryFileStream.Position);

//
重定向模式2的处理

end

else
if
RedirectMode
=
REDIRECT_MODE_2
then

begin

QQWryFileStream.ReadData(CountrySecondOffset,
3);

CountryMsg
:=
ReadString(CountrySecondOffset);

AreaMsg
:=
ReadArea(IPLocationOffset
+
8);

//
不是重定向模式的处理,存放的即是IP地址信息

end

else

begin

CountryMsg
:=
ReadString(QQWryFileStream.Position
-
1);

AreaMsg
:=
ReadArea(QQWryFileStream.Position);

end;

Result
:=
TStringlist.Create;

Result.Add(CountryMsg);

Result.Add(AreaMsg);

end;

function
TIPLocation.GetIPMsg(IPRecordID:
Cardinal):
TStringlist;

var

aryStartIP:
array
[1
..
4]
of
byte;

strStartIP:
string;

EndIPOffset:
Cardinal;

aryEndIP:
array
[1
..
4]
of
byte;

strEndIP:
string;

i:
integer;

begin

EndIPOffset
:=
0;

//
根据记录ID号移到该记录号的索引处

QQWryFileStream.Seek(FirstIPIndexOffset
+
(IPRecordID
-
1)
*
7,

soFromBeginning);

//
索引的前4个字节为起始IP地址

QQWryFileStream.Read(aryStartIP,
4);

//
后3个字节是内容区域的偏移值

//
QQWryFileStream.Read(EndIPOffset, 3);

QQWryFileStream.ReadData(EndIPOffset,
3);

//
移至内容区域

QQWryFileStream.Seek(EndIPOffset,
soFromBeginning);

//
内容区域的前4个字节为终止IP地址

QQWryFileStream.Read(aryEndIP,
4);

//
将起止IP地址转换为点分的形式

strStartIP
:=
'';

for
i
:=
4
downto
1
do

begin

if
i
<>
1
then

strStartIP
:=
strStartIP
+
IntToStr(aryStartIP[i])
+
'.'

else

strStartIP
:=
strStartIP
+
IntToStr(aryStartIP[i]);

end;

strEndIP
:=
'';

for
i
:=
4
downto
1
do

begin

if
i
<>
1
then

strEndIP
:=
strEndIP
+
IntToStr(aryEndIP[i])
+
'.'

else

strEndIP
:=
strEndIP
+
IntToStr(aryEndIP[i]);

end;

Result
:=
TStringlist.Create;

Result.Add(strStartIP);

Result.Add(strEndIP);

//
获取该条记录下的IP地址信息

//
以下三者是统一的:①内容区域的偏移值 ②终止IP地址的存放位置 ③国家信息紧接在终止IP地址存放位置后

Result.AddStrings(GetIPLocation(EndIPOffset));

end;

function
TIPLocation.GetIPRecordID(IP:
string):
Cardinal;

function
SearchIPRecordID(IPRecordFrom,
IPRecordTo,
IPValue:
Cardinal)

:
Cardinal;

var

CompareIPValue1,
CompareIPValue2:
Cardinal;

begin

Result
:=
0;

CompareIPValue1
:=
0;

CompareIPValue2
:=
0;

QQWryFileStream.Seek(FirstIPIndexOffset
+
((IPRecordTo
-
IPRecordFrom)
div
2

+
IPRecordFrom
-
1)
*
7,
soFromBeginning);

QQWryFileStream.Read(CompareIPValue1,
4);

QQWryFileStream.Seek(FirstIPIndexOffset
+
((IPRecordTo
-
IPRecordFrom)
div
2

+
IPRecordFrom)
*
7,
soFromBeginning);

QQWryFileStream.Read(CompareIPValue2,
4);

//
找到了

if
(IPValue
>=
CompareIPValue1)
and
(IPValue
<
CompareIPValue2)
then

begin

Result
:=
(IPRecordTo
-
IPRecordFrom)
div
2
+
IPRecordFrom;

end

else

//
后半段找

if
IPValue
>
CompareIPValue1
then

begin

Result
:=
SearchIPRecordID((IPRecordTo
-
IPRecordFrom)
div
2
+

IPRecordFrom
+
1,
IPRecordTo,
IPValue);

end

else

//
前半段找

if
IPValue
<
CompareIPValue1
then

begin

Result
:=
SearchIPRecordID(IPRecordFrom,
(IPRecordTo
-
IPRecordFrom)

div
2
+
IPRecordFrom
-
1,
IPValue);

end;

end;

begin

Result
:=
SearchIPRecordID(1,
GetIPRecordNum,
GetIPValue(IP));

end;

function
TIPLocation.GetIPRecordNum:
Cardinal;

begin

Result
:=
IPRecordNum;

end;

function
TIPLocation.GetIPValue(IP:
string):
Cardinal;

var

tsIP:
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

tsIP
:=
SplitStringToStringlist(IP,
'.');

Result
:=
0;

for
i
:=
3
downto
0
do

begin

Result
:=
Result
+
StrToInt(tsIP[i])
*
trunc(power(256,
3
-
i));

end;

end;

function
TIPLocation.GetLocation(IP:
string):
String;

begin

FLock.Enter;

try

Result
:=
GetIPMsg(GetIPRecordID(IP))[2];

finally

FLock.Leave;

end;

end;

function
TIPLocation.GetQQWryDataFrom:
string;

begin

Result
:=
GetIPMsg(GetIPRecordNum)[2];

end;

function
TIPLocation.GetQQWryDate:
TDate;

var

DateString:
string;

begin

DateString
:=
GetIPMsg(GetIPRecordNum)[3];

DateString
:=
copy(DateString,
1,
pos('IP数据',
DateString)
-
1);

DateString
:=
StringReplace(DateString,
'年',
'-',

[rfReplaceAll,
rfIgnoreCase]);

DateString
:=
StringReplace(DateString,
'月',
'-',

[rfReplaceAll,
rfIgnoreCase]);

DateString
:=
StringReplace(DateString,
'日',
'-',

[rfReplaceAll,
rfIgnoreCase]);

Result
:=
StrToDate(DateString);

end;

function
TIPLocation.GetQQWryFileName:
string;

begin

Result
:=
QQWryFileName;

end;

function
TIPLocation.GetQQWryFileSize:
Cardinal;

begin

Result
:=
QQWryFileSize;

end;

initialization

finalization

if
__IPLocation
<>
nil
then

__IPLocation.Free;

end.

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: