根据LumaQQ改写而成.
1using System;
2using System.IO;
3using System.Text;
4
5namespace BDQQ.Data
6{
7 /// <summary>
8 /// QQWry 的摘要说明。
9 /// </summary>
10 public class QQWry
11 {
12 #region 第一种模式
13 /// <summary>
14 /// 第一种模式
15 /// </summary>
16 #endregion
17 private const byte REDIRECT_MODE_1 = 0x01;
18
19 #region 第二种模式
20 /// <summary>
21 /// 第二种模式
22 /// </summary>
23 #endregion
24 private const byte REDIRECT_MODE_2 = 0x02;
25
26 #region 每条记录长度
27 /// <summary>
28 /// 每条记录长度
29 /// </summary>
30 #endregion
31 private const int IP_RECORD_LENGTH = 7;
32
33 #region 数据库文件
34 /// <summary>
35 /// 文件对象
36 /// </summary>
37 #endregion
38 private FileStream ipFile;
39
40 private const string unCountry = "未知国家";
41 private const string unArea = "未知地区";
42
43 #region 索引开始位置
44 /// <summary>
45 /// 索引开始位置
46 /// </summary>
47 #endregion
48 private long ipBegin;
49
50 #region 索引结束位置
51 /// <summary>
52 /// 索引结束位置
53 /// </summary>
54 #endregion
55 private long ipEnd;
56
57 #region IP地址对象
58 /// <summary>
59 /// IP对象
60 /// </summary>
61 #endregion
62 private IPLocation loc;
63
64 #region 存储文本内容
65 /// <summary>
66 /// 存储文本内容
67 /// </summary>
68 #endregion
69 private byte[] buf;
70
71 #region 存储3字节
72 /// <summary>
73 /// 存储3字节
74 /// </summary>
75 #endregion
76 private byte[] b3;
77
78 #region 存储4字节
79 /// <summary>
80 /// 存储4字节IP地址
81 /// </summary>
82 #endregion
83 private byte[] b4;
84
85 #region 构造函数
86 /// <summary>
87 /// 构造函数
88 /// </summary>
89 /// <param name="ipfile">IP数据库文件绝对路径</param>
90 #endregion
91 public QQWry( string ipfile )
92 {
93 buf = new byte[100];
94 b3 = new byte[3];
95 b4 = new byte[4];
96 try
97 {
98 ipFile = new FileStream( ipfile,FileMode.Open );
99 }
100 catch( Exception ex )
101 {
102 throw new Exception( ex.Message );
103 }
104 ipBegin = readLong4(0);
105 ipEnd = readLong4(4);
106 loc = new IPLocation();
107 }
108
109
110 #region 根据IP地址搜索
111 /// <summary>
112 /// 搜索IP地址搜索
113 /// </summary>
114 /// <param name="ip"></param>
115 /// <returns></returns>
116 #endregion
117 public IPLocation SearchIPLocation( string ip )
118 {
119 //将字符IP转换为字节
120 string[] ipSp = ip.Split('.');
121 if( ipSp.Length != 4 )
122 {
123 throw new ArgumentOutOfRangeException( "不是合法的IP地址!" );
124 }
125 byte[] IP = new byte[4];
126 for( int i = 0; i < IP.Length ; i++ )
127 {
128 IP[i] = (byte)(Int32.Parse( ipSp[i] ) & 0xFF) ;
129 }
130
131 IPLocation local = null;
132 long offset = locateIP( IP );
133
134 if( offset != -1 )
135 {
136 local = getIPLocation( offset );
137 }
138
139 if( local == null )
140 {
141 local = new IPLocation();
142 local.area = unArea;
143 local.country = unCountry;
144 }
145 return local;
146 }
147
148
149 #region 取得具体信息
150 /// <summary>
151 /// 取得具体信息
152 /// </summary>
153 /// <param name="offset"></param>
154 /// <returns></returns>
155 #endregion
156 private IPLocation getIPLocation( long offset )
157 {
158 ipFile.Position = offset + 4;
159 //读取第一个字节判断是否是标志字节
160 byte one = (byte)ipFile.ReadByte();
161 if( one == REDIRECT_MODE_1 )
162 {
163 //第一种模式
164 //读取国家偏移
165 long countryOffset = readLong3();
166 //转至偏移处
167 ipFile.Position = countryOffset;
168 //再次检查标志字节
169 byte b = (byte)ipFile.ReadByte();
170 if( b == REDIRECT_MODE_2 )
171 {
172 loc.country = readString( readLong3() );
173 ipFile.Position = countryOffset + 4;
174 }
175 else
176 loc.country = readString( countryOffset );
177
178 //读取地区标志
179 loc.area = readArea( ipFile.Position );
180
181 }
182 else if( one == REDIRECT_MODE_2 )
183 {
184 //第二种模式
185 loc.country = readString( readLong3() );
186 loc.area = readArea( offset + 8 );
187 }
188 else
189 {
190 //普通模式
191 loc.country = readString( --ipFile.Position );
192 loc.area = readString( ipFile.Position );
193 }
194 return loc;
195 }
196
197
198 #region 取得地区信息
199 /// <summary>
200 /// 读取地区名称
201 /// </summary>
202 /// <param name="offset"></param>
203 /// <returns></returns>
204 #endregion
205 private string readArea( long offset )
206 {
207 ipFile.Position = offset;
208 byte one = (byte)ipFile.ReadByte();
209 if( one == REDIRECT_MODE_1 || one == REDIRECT_MODE_2 )
210 {
211 long areaOffset = readLong3( offset + 1 );
212 if( areaOffset == 0 )
213 return unArea;
214 else
215 {
216 return readString( areaOffset );
217 }
218 }
219 else
220 {
221 return readString( offset );
222 }
223 }
224
225
226 #region 读取字符串
227 /// <summary>
228 /// 读取字符串
229 /// </summary>
230 /// <param name="offset"></param>
231 /// <returns></returns>
232 #endregion
233 private string readString( long offset )
234 {
235 ipFile.Position = offset;
236 int i = 0;
237 for(i = 0, buf[i]=(byte)ipFile.ReadByte();buf[i] != (byte)(0);buf[++i]=(byte)ipFile.ReadByte());
238
239 if( i > 0 )
240 return Encoding.Default.GetString( buf,0,i );
241 else
242 return "";
243 }
244
245
246 #region 查找IP地址所在的绝对偏移量
247 /// <summary>
248 /// 查找IP地址所在的绝对偏移量
249 /// </summary>
250 /// <param name="ip"></param>
251 /// <returns></returns>
252 #endregion
253 private long locateIP( byte[] ip )
254 {
255 long m = 0;
256 int r;
257
258 //比较第一个IP项
259 readIP( ipBegin, b4 );
260 r = compareIP( ip,b4);
261 if( r == 0 )
262 return ipBegin;
263 else if( r < 0 )
264 return -1;
265 //开始二分搜索
266 for( long i = ipBegin,j=ipEnd; i<j; )
267 {
268 m = this.getMiddleOffset( i,j );
269 readIP( m,b4 );
270 r = compareIP( ip,b4 );
271 if( r > 0 )
272 i = m;
273 else if( r < 0 )
274 {
275 if( m == j )
276 {
277 j -= IP_RECORD_LENGTH;
278 m = j;
279 }
280 else
281 {
282 j = m;
283 }
284 }
285 else
286 return readLong3( m+4 );
287 }
288 m = readLong3( m+4 );
289 readIP( m,b4 );
290 r = compareIP( ip,b4 );
291 if( r <= 0 )
292 return m;
293 else
294 return -1;
295 }
296
297
298 #region 读出4字节的IP地址
299 /// <summary>
300 /// 从当前位置读取四字节,此四字节是IP地址
301 /// </summary>
302 /// <param name="offset"></param>
303 /// <param name="ip"></param>
304 #endregion
305 private void readIP( long offset, byte[] ip )
306 {
307 ipFile.Position = offset;
308 ipFile.Read( ip,0,ip.Length );
309 byte tmp = ip[0];
310 ip[0] = ip[3];
311 ip[3] = tmp;
312 tmp = ip[1];
313 ip[1] = ip[2];
314 ip[2] = tmp;
315 }
316
317
318 #region 比较IP地址是否相同
319 /// <summary>
320 /// 比较IP地址是否相同
321 /// </summary>
322 /// <param name="ip"></param>
323 /// <param name="beginIP"></param>
324 /// <returns>0:相等,1:ip大于beginIP,-1:小于</returns>
325 #endregion
326 private int compareIP( byte[] ip, byte[] beginIP )
327 {
328 for( int i = 0; i < 4; i++ )
329 {
330 int r = compareByte( ip[i],beginIP[i] );
331 if( r != 0 )
332 return r;
333 }
334 return 0;
335 }
336
337
338 #region 比较两个字节是否相等
339 /// <summary>
340 /// 比较两个字节是否相等
341 /// </summary>
342 /// <param name="bsrc"></param>
343 /// <param name="bdst"></param>
344 /// <returns></returns>
345 #endregion
346 private int compareByte( byte bsrc, byte bdst )
347 {
348 if( ( bsrc&0xFF ) > ( bdst&0xFF ) )
349 return 1;
350 else if( (bsrc ^ bdst) == 0 )
351 return 0;
352 else
353 return -1;
354 }
355
356
357 #region 根据当前位置读取4字节
358 /// <summary>
359 /// 从当前位置读取4字节,转换为长整型
360 /// </summary>
361 /// <param name="offset"></param>
362 /// <returns></returns>
363 #endregion
364 private long readLong4( long offset )
365 {
366 long ret = 0;
367 ipFile.Position = offset;
368 ret |= ( ipFile.ReadByte() & 0xFF );
369 ret |= ( ( ipFile.ReadByte() << 8 ) & 0xFF00 );
370 ret |= ( ( ipFile.ReadByte() << 16 ) & 0xFF0000 );
371 ret |= ( ( ipFile.ReadByte() << 24 ) & 0xFF000000 );
372 return ret;
373 }
374
375
376 #region 根据当前位置,读取3字节
377 /// <summary>
378 /// 根据当前位置,读取3字节
379 /// </summary>
380 /// <param name="offset"></param>
381 /// <returns></returns>
382 #endregion
383 private long readLong3( long offset )
384 {
385 long ret = 0;
386 ipFile.Position = offset;
387 ret |= ( ipFile.ReadByte() & 0xFF );
388 ret |= ( (ipFile.ReadByte() << 8 ) & 0xFF00 );
389 ret |= ( (ipFile.ReadByte() << 16 ) & 0xFF0000 );
390 return ret;
391 }
392
393
394 #region 从当前位置读取3字节
395 /// <summary>
396 /// 从当前位置读取3字节
397 /// </summary>
398 /// <returns></returns>
399 #endregion
400 private long readLong3()
401 {
402 long ret = 0;
403 ret |= ( ipFile.ReadByte() & 0xFF );
404 ret |= ( (ipFile.ReadByte() << 8 ) & 0xFF00 );
405 ret |= ( (ipFile.ReadByte() << 16 ) & 0xFF0000 );
406 return ret;
407 }
408
409
410 #region 取得begin和end之间的偏移量
411 /// <summary>
412 /// 取得begin和end中间的偏移
413 /// </summary>
414 /// <param name="begin"></param>
415 /// <param name="end"></param>
416 /// <returns></returns>
417 #endregion
418 private long getMiddleOffset( long begin, long end )
419 {
420 long records = ( end - begin ) / IP_RECORD_LENGTH;
421 records >>= 1;
422 if( records == 0 )
423 records = 1;
424 return begin + records * IP_RECORD_LENGTH;
425 }
426 } //class QQWry
427
428 public class IPLocation
429 {
430 public String country;
431 public String area;
432
433 public IPLocation()
434 {
435 country = area = "";
436 }
437
438 public IPLocation getCopy()
439 {
440 IPLocation ret = new IPLocation();
441 ret.country = country;
442 ret.area = area;
443 return ret;
444 }
445 }
446}
447
1using System;
2using System.IO;
3using System.Text;
4
5namespace BDQQ.Data
6{
7 /// <summary>
8 /// QQWry 的摘要说明。
9 /// </summary>
10 public class QQWry
11 {
12 #region 第一种模式
13 /// <summary>
14 /// 第一种模式
15 /// </summary>
16 #endregion
17 private const byte REDIRECT_MODE_1 = 0x01;
18
19 #region 第二种模式
20 /// <summary>
21 /// 第二种模式
22 /// </summary>
23 #endregion
24 private const byte REDIRECT_MODE_2 = 0x02;
25
26 #region 每条记录长度
27 /// <summary>
28 /// 每条记录长度
29 /// </summary>
30 #endregion
31 private const int IP_RECORD_LENGTH = 7;
32
33 #region 数据库文件
34 /// <summary>
35 /// 文件对象
36 /// </summary>
37 #endregion
38 private FileStream ipFile;
39
40 private const string unCountry = "未知国家";
41 private const string unArea = "未知地区";
42
43 #region 索引开始位置
44 /// <summary>
45 /// 索引开始位置
46 /// </summary>
47 #endregion
48 private long ipBegin;
49
50 #region 索引结束位置
51 /// <summary>
52 /// 索引结束位置
53 /// </summary>
54 #endregion
55 private long ipEnd;
56
57 #region IP地址对象
58 /// <summary>
59 /// IP对象
60 /// </summary>
61 #endregion
62 private IPLocation loc;
63
64 #region 存储文本内容
65 /// <summary>
66 /// 存储文本内容
67 /// </summary>
68 #endregion
69 private byte[] buf;
70
71 #region 存储3字节
72 /// <summary>
73 /// 存储3字节
74 /// </summary>
75 #endregion
76 private byte[] b3;
77
78 #region 存储4字节
79 /// <summary>
80 /// 存储4字节IP地址
81 /// </summary>
82 #endregion
83 private byte[] b4;
84
85 #region 构造函数
86 /// <summary>
87 /// 构造函数
88 /// </summary>
89 /// <param name="ipfile">IP数据库文件绝对路径</param>
90 #endregion
91 public QQWry( string ipfile )
92 {
93 buf = new byte[100];
94 b3 = new byte[3];
95 b4 = new byte[4];
96 try
97 {
98 ipFile = new FileStream( ipfile,FileMode.Open );
99 }
100 catch( Exception ex )
101 {
102 throw new Exception( ex.Message );
103 }
104 ipBegin = readLong4(0);
105 ipEnd = readLong4(4);
106 loc = new IPLocation();
107 }
108
109
110 #region 根据IP地址搜索
111 /// <summary>
112 /// 搜索IP地址搜索
113 /// </summary>
114 /// <param name="ip"></param>
115 /// <returns></returns>
116 #endregion
117 public IPLocation SearchIPLocation( string ip )
118 {
119 //将字符IP转换为字节
120 string[] ipSp = ip.Split('.');
121 if( ipSp.Length != 4 )
122 {
123 throw new ArgumentOutOfRangeException( "不是合法的IP地址!" );
124 }
125 byte[] IP = new byte[4];
126 for( int i = 0; i < IP.Length ; i++ )
127 {
128 IP[i] = (byte)(Int32.Parse( ipSp[i] ) & 0xFF) ;
129 }
130
131 IPLocation local = null;
132 long offset = locateIP( IP );
133
134 if( offset != -1 )
135 {
136 local = getIPLocation( offset );
137 }
138
139 if( local == null )
140 {
141 local = new IPLocation();
142 local.area = unArea;
143 local.country = unCountry;
144 }
145 return local;
146 }
147
148
149 #region 取得具体信息
150 /// <summary>
151 /// 取得具体信息
152 /// </summary>
153 /// <param name="offset"></param>
154 /// <returns></returns>
155 #endregion
156 private IPLocation getIPLocation( long offset )
157 {
158 ipFile.Position = offset + 4;
159 //读取第一个字节判断是否是标志字节
160 byte one = (byte)ipFile.ReadByte();
161 if( one == REDIRECT_MODE_1 )
162 {
163 //第一种模式
164 //读取国家偏移
165 long countryOffset = readLong3();
166 //转至偏移处
167 ipFile.Position = countryOffset;
168 //再次检查标志字节
169 byte b = (byte)ipFile.ReadByte();
170 if( b == REDIRECT_MODE_2 )
171 {
172 loc.country = readString( readLong3() );
173 ipFile.Position = countryOffset + 4;
174 }
175 else
176 loc.country = readString( countryOffset );
177
178 //读取地区标志
179 loc.area = readArea( ipFile.Position );
180
181 }
182 else if( one == REDIRECT_MODE_2 )
183 {
184 //第二种模式
185 loc.country = readString( readLong3() );
186 loc.area = readArea( offset + 8 );
187 }
188 else
189 {
190 //普通模式
191 loc.country = readString( --ipFile.Position );
192 loc.area = readString( ipFile.Position );
193 }
194 return loc;
195 }
196
197
198 #region 取得地区信息
199 /// <summary>
200 /// 读取地区名称
201 /// </summary>
202 /// <param name="offset"></param>
203 /// <returns></returns>
204 #endregion
205 private string readArea( long offset )
206 {
207 ipFile.Position = offset;
208 byte one = (byte)ipFile.ReadByte();
209 if( one == REDIRECT_MODE_1 || one == REDIRECT_MODE_2 )
210 {
211 long areaOffset = readLong3( offset + 1 );
212 if( areaOffset == 0 )
213 return unArea;
214 else
215 {
216 return readString( areaOffset );
217 }
218 }
219 else
220 {
221 return readString( offset );
222 }
223 }
224
225
226 #region 读取字符串
227 /// <summary>
228 /// 读取字符串
229 /// </summary>
230 /// <param name="offset"></param>
231 /// <returns></returns>
232 #endregion
233 private string readString( long offset )
234 {
235 ipFile.Position = offset;
236 int i = 0;
237 for(i = 0, buf[i]=(byte)ipFile.ReadByte();buf[i] != (byte)(0);buf[++i]=(byte)ipFile.ReadByte());
238
239 if( i > 0 )
240 return Encoding.Default.GetString( buf,0,i );
241 else
242 return "";
243 }
244
245
246 #region 查找IP地址所在的绝对偏移量
247 /// <summary>
248 /// 查找IP地址所在的绝对偏移量
249 /// </summary>
250 /// <param name="ip"></param>
251 /// <returns></returns>
252 #endregion
253 private long locateIP( byte[] ip )
254 {
255 long m = 0;
256 int r;
257
258 //比较第一个IP项
259 readIP( ipBegin, b4 );
260 r = compareIP( ip,b4);
261 if( r == 0 )
262 return ipBegin;
263 else if( r < 0 )
264 return -1;
265 //开始二分搜索
266 for( long i = ipBegin,j=ipEnd; i<j; )
267 {
268 m = this.getMiddleOffset( i,j );
269 readIP( m,b4 );
270 r = compareIP( ip,b4 );
271 if( r > 0 )
272 i = m;
273 else if( r < 0 )
274 {
275 if( m == j )
276 {
277 j -= IP_RECORD_LENGTH;
278 m = j;
279 }
280 else
281 {
282 j = m;
283 }
284 }
285 else
286 return readLong3( m+4 );
287 }
288 m = readLong3( m+4 );
289 readIP( m,b4 );
290 r = compareIP( ip,b4 );
291 if( r <= 0 )
292 return m;
293 else
294 return -1;
295 }
296
297
298 #region 读出4字节的IP地址
299 /// <summary>
300 /// 从当前位置读取四字节,此四字节是IP地址
301 /// </summary>
302 /// <param name="offset"></param>
303 /// <param name="ip"></param>
304 #endregion
305 private void readIP( long offset, byte[] ip )
306 {
307 ipFile.Position = offset;
308 ipFile.Read( ip,0,ip.Length );
309 byte tmp = ip[0];
310 ip[0] = ip[3];
311 ip[3] = tmp;
312 tmp = ip[1];
313 ip[1] = ip[2];
314 ip[2] = tmp;
315 }
316
317
318 #region 比较IP地址是否相同
319 /// <summary>
320 /// 比较IP地址是否相同
321 /// </summary>
322 /// <param name="ip"></param>
323 /// <param name="beginIP"></param>
324 /// <returns>0:相等,1:ip大于beginIP,-1:小于</returns>
325 #endregion
326 private int compareIP( byte[] ip, byte[] beginIP )
327 {
328 for( int i = 0; i < 4; i++ )
329 {
330 int r = compareByte( ip[i],beginIP[i] );
331 if( r != 0 )
332 return r;
333 }
334 return 0;
335 }
336
337
338 #region 比较两个字节是否相等
339 /// <summary>
340 /// 比较两个字节是否相等
341 /// </summary>
342 /// <param name="bsrc"></param>
343 /// <param name="bdst"></param>
344 /// <returns></returns>
345 #endregion
346 private int compareByte( byte bsrc, byte bdst )
347 {
348 if( ( bsrc&0xFF ) > ( bdst&0xFF ) )
349 return 1;
350 else if( (bsrc ^ bdst) == 0 )
351 return 0;
352 else
353 return -1;
354 }
355
356
357 #region 根据当前位置读取4字节
358 /// <summary>
359 /// 从当前位置读取4字节,转换为长整型
360 /// </summary>
361 /// <param name="offset"></param>
362 /// <returns></returns>
363 #endregion
364 private long readLong4( long offset )
365 {
366 long ret = 0;
367 ipFile.Position = offset;
368 ret |= ( ipFile.ReadByte() & 0xFF );
369 ret |= ( ( ipFile.ReadByte() << 8 ) & 0xFF00 );
370 ret |= ( ( ipFile.ReadByte() << 16 ) & 0xFF0000 );
371 ret |= ( ( ipFile.ReadByte() << 24 ) & 0xFF000000 );
372 return ret;
373 }
374
375
376 #region 根据当前位置,读取3字节
377 /// <summary>
378 /// 根据当前位置,读取3字节
379 /// </summary>
380 /// <param name="offset"></param>
381 /// <returns></returns>
382 #endregion
383 private long readLong3( long offset )
384 {
385 long ret = 0;
386 ipFile.Position = offset;
387 ret |= ( ipFile.ReadByte() & 0xFF );
388 ret |= ( (ipFile.ReadByte() << 8 ) & 0xFF00 );
389 ret |= ( (ipFile.ReadByte() << 16 ) & 0xFF0000 );
390 return ret;
391 }
392
393
394 #region 从当前位置读取3字节
395 /// <summary>
396 /// 从当前位置读取3字节
397 /// </summary>
398 /// <returns></returns>
399 #endregion
400 private long readLong3()
401 {
402 long ret = 0;
403 ret |= ( ipFile.ReadByte() & 0xFF );
404 ret |= ( (ipFile.ReadByte() << 8 ) & 0xFF00 );
405 ret |= ( (ipFile.ReadByte() << 16 ) & 0xFF0000 );
406 return ret;
407 }
408
409
410 #region 取得begin和end之间的偏移量
411 /// <summary>
412 /// 取得begin和end中间的偏移
413 /// </summary>
414 /// <param name="begin"></param>
415 /// <param name="end"></param>
416 /// <returns></returns>
417 #endregion
418 private long getMiddleOffset( long begin, long end )
419 {
420 long records = ( end - begin ) / IP_RECORD_LENGTH;
421 records >>= 1;
422 if( records == 0 )
423 records = 1;
424 return begin + records * IP_RECORD_LENGTH;
425 }
426 } //class QQWry
427
428 public class IPLocation
429 {
430 public String country;
431 public String area;
432
433 public IPLocation()
434 {
435 country = area = "";
436 }
437
438 public IPLocation getCopy()
439 {
440 IPLocation ret = new IPLocation();
441 ret.country = country;
442 ret.area = area;
443 return ret;
444 }
445 }
446}
447