using System;

using System.Collections.Generic;

using System.Text;

using System.IO;

namespace 纯真IP数据库研究

{

    ///<summary>

    /// 提供从纯真IP数据库搜索IP信息的方法;

    /// 感谢LumaQQ提供纯真IP数据库格式文档;

    /// ----HeDaode 2007-12-28 四川教育学院

    ///</summary>

    public class IPSearch

    {

        FileStream ipFile;

        long ip;

        string ipfilePath;


        ///<summary>

        /// 构造函数

        ///</summary>

        ///<param name="ipfilePath">纯真IP数据库路径</param>

        public IPSearch(string ipfilePath)

        {

            this.ipfilePath = ipfilePath;

        }

        //测试

        static void Main(string[] args)

        {

            string ipfilePath = @"C:\Documents and Settings\Daode\桌面\qqwry\QQWry.dat";

            IPSearch ipSearch = new IPSearch(ipfilePath);

            string ip = "72.51.27.51";

            IPSearch.IPLocation loc = ipSearch.GetIPLocation(ip);

            Console.WriteLine("你查的ip是:{0} 地理位置:{1} {2}", ip, loc.country, loc.area);

            Console.ReadKey();

        }

        ///<summary>

        /// 地理位置,包括国家和地区

        ///</summary>

        public struct IPLocation

        {

            public string country, area;

        }

        ///<summary>

        /// 获取指定IP所在地理位置

        ///</summary>

        ///<param name="strIP">要查询的IP地址</param>

        ///<returns></returns>

        public IPLocation GetIPLocation(string strIP)

        {

            ip = IPToLong(strIP);

            ipFile = new FileStream(ipfilePath, FileMode.Open, FileAccess.Read);

            long[] ipArray = BlockToArray(ReadIPBlock());

            long offset = SearchIP(ipArray, 0, ipArray.Length - 1) * 7 + 4;

            ipFile.Position += offset;//跳过起始IP

            ipFile.Position = ReadLongX(3) + 4;//跳过结束IP


            IPLocation loc = new IPLocation();

            int flag = ipFile.ReadByte();//读取标志

            if (flag == 1)//表示国家和地区被转向

            {

                ipFile.Position = ReadLongX(3);

                flag = ipFile.ReadByte();//再读标志

            }

            long countryOffset = ipFile.Position;

            loc.country = ReadString(flag);


            if (flag == 2)

            {

                ipFile.Position = countryOffset + 3;

            }

            flag = ipFile.ReadByte();

            loc.area = ReadString(flag);


            ipFile.Close();

            ipFile = null;

            return loc;

        }

        ///<summary>

        /// 将字符串形式的IP转换位long

        ///</summary>

        ///<param name="strIP"></param>

        ///<returns></returns>

        public long IPToLong(string strIP)

        {

            byte[] ip_bytes = new byte[8];

            string[] strArr = strIP.Split(new char[] { '.' });

            for (int i = 0; i < 4; i++)

            {

                ip_bytes[i] = byte.Parse(strArr[3 - i]);

            }

            return BitConverter.ToInt64(ip_bytes, 0);

        }

        ///<summary>

        /// 将索引区字节块中的起始IP转换成Long数组

        ///</summary>

        ///<param name="ipBlock"></param>

        long[] BlockToArray(byte[] ipBlock)

        {

            long[] ipArray = new long[ipBlock.Length / 7];

            int ipIndex = 0;

            byte[] temp = new byte[8];

            for (int i = 0; i < ipBlock.Length; i += 7)

            {

                Array.Copy(ipBlock, i, temp, 0, 4);

                ipArray[ipIndex] = BitConverter.ToInt64(temp, 0);

                ipIndex++;

            }

            return ipArray;

        }

        ///<summary>

        /// 从IP数组中搜索指定IP并返回其索引

        ///</summary>

        ///<param name="ipArray">IP数组</param>

        ///<param name="start">指定搜索的起始位置</param>

        ///<param name="end">指定搜索的结束位置</param>

        ///<returns></returns>

        int SearchIP(long[] ipArray, int start, int end)

        {

            int middle = (start + end) / 2;

            if (middle == start)

                return middle;

            else if (ip < ipArray[middle])

                return SearchIP(ipArray, start, middle);

            else

                return SearchIP(ipArray, middle, end);

        }

        ///<summary>

        /// 读取IP文件中索引区块

        ///</summary>

        ///<returns></returns>

        byte[] ReadIPBlock()

        {

            long startPosition = ReadLongX(4);

            long endPosition = ReadLongX(4);

            long count = (endPosition - startPosition) / 7 + 1;//总记录数

            ipFile.Position = startPosition;

            byte[] ipBlock = new byte[count * 7];

            ipFile.Read(ipBlock, 0, ipBlock.Length);

            ipFile.Position = startPosition;

            return ipBlock;

        }

        ///<summary>

        /// 从IP文件中读取指定字节并转换位long

        ///</summary>

        ///<param name="bytesCount">需要转换的字节数,主意不要超过8字节</param>

        ///<returns></returns>

        long ReadLongX(int bytesCount)

        {

            byte[] _bytes = new byte[8];

            ipFile.Read(_bytes, 0, bytesCount);

            return BitConverter.ToInt64(_bytes, 0);

        }

        ///<summary>

        /// 从IP文件中读取字符串

        ///</summary>

        ///<param name="flag">转向标志</param>

        ///<returns></returns>

        string ReadString(int flag)

        {

            if (flag == 1 || flag == 2)//转向标志

                ipFile.Position = ReadLongX(3);

            else

                ipFile.Position -= 1;


            List<byte> list = new List<byte>();

            byte b = (byte)ipFile.ReadByte();

            while (b > 0)

            {

                list.Add(b);

                b = (byte)ipFile.ReadByte();

            }

            return Encoding.Default.GetString(list.ToArray());

        }

    }

}