# encoding: utf-8 require 'bindata' require 'ipaddr' require 'ip2location_ruby/ip2location_config' require 'ip2location_ruby/database_config' require 'ip2location_ruby/i2l_float_data' require 'ip2location_ruby/i2l_string_data' require 'ip2location_ruby/i2l_ip_data' require 'ip2location_ruby/ip2location_record' class Ip2location attr_accessor :record_class, :v4, :file, :db_index, :count, :base_addr, :ipno, :count, :record, :database, :columns, :ip_version def open(url) self.file = File.open(File.expand_path url, 'rb') i2l = Ip2locationConfig.read(file) self.db_index = i2l.databasetype self.count = i2l.databasecount + 0 self.base_addr = i2l.databaseaddr - 1 self.columns = i2l.databasecolumn + 0 self.database = DbConfig.setup_database(self.db_index) self.ip_version = (i2l.ipversion == 0 ? 4 : 6) self.record_class = (Ip2LocationRecord.init database, self.ip_version) self end def get_all(ip) ipno = IPAddr.new(ip, Socket::AF_UNSPEC) self.v4 = ipno.ipv4? && self.ip_version == 4 ipnum = ipno.to_i + 0 mid = self.count/2 col_length = columns * 4 low = 0 high = count return self.record = bsearch(low, high, ipnum, self.base_addr, col_length) end def get_from_to(mid, base_addr, col_length) if v4 from_base = ( base_addr + mid * col_length) else from_base = ( base_addr + mid * (col_length + 12)) end file.seek(from_base) ip_from = file.read(4).unpack('L')[0] file.seek(from_base + col_length) ip_to = file.read(4).unpack('L')[0] [ip_from, ip_to] end def bsearch(low, high, ipnum, base_addr, col_length) mid = (high + low)/2 return nil if low == mid ip_from, ip_to = get_from_to(mid, base_addr, col_length) if ipnum < ip_from low = low high = mid return bsearch(low, high, ipnum, base_addr, col_length) elsif ipnum >= ip_to low = mid high = high return bsearch(low, high, ipnum, base_addr, col_length) else from_base = ( base_addr + mid * col_length) file.seek(from_base) return self.record_class.read(file) end end end