根据LumaQQ改写而成.

  1
using 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            forint 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            forlong 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            forint 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
posted on 2005-07-08 10:58  王员外  阅读(2474)  评论(0编辑  收藏  举报