ip2region_private/binding/ruby/ip_2_region.rb

76 lines
1.8 KiB
Ruby

class Ip2Region
INDEX_BLOCK_LENGTH = 12
TOTAL_HEADER_LENGTH = 8192
attr_accessor :f, :headerSip, :headerPtr, :headerLen, :indexSPtr, :indexLPtr, :indexCount, :dbBinStr
def initialize(dbfile = "../../data/ip2region.db")
initDatabase(dbfile)
true
end
def initDatabase(dbfile = "ip2region.db")
@dbBinStr = File.open(dbfile, 'rb').read
@indexSPtr = getLong(@dbBinStr, 0)
@indexLPtr = getLong(@dbBinStr, 4)
@indexCount = ((indexLPtr - indexSPtr) / INDEX_BLOCK_LENGTH).to_i + 1
# puts "#{@indexSPtr} #{@indexLPtr} #{@indexCount}"
end
def memorySearch(ip)
ip = ip2long(ip)
l, h, dataPtr = 0, indexCount , 0
# print(l,h,dataPtr)
while l <= h
m = (l + h) >> 1
p = m * INDEX_BLOCK_LENGTH + indexSPtr
# puts "m = #{m}, p = #{p}"
sip = getLong(@dbBinStr, p)
# puts "sip = #{sip}"
if ip < sip
h = m - 1
else
eip = getLong(@dbBinStr, p + 4)
if ip > eip
l = m + 1
else
dataPtr = getLong(@dbBinStr, p + 8)
break
end
end
end
if dataPtr == 0
return nil
end
returnData(dataPtr)
end
def returnData(dataPtr)
dataLen = (dataPtr >> 24) & 0xFF
dataPtr = dataPtr & 0x00FFFFFF
data = @dbBinStr[dataPtr, dataLen]
# @dbBinStr.seek(dataPtr)
# data = @dbBinStr.read(dataLen)
return {
:city_id => getLong(data, 0),
:region => data[4..-1].force_encoding("utf-8")
}
end
def getLong(b, offset)
if (b[offset..offset+3] || []).length == 4
# puts "unpack = #{b[offset..offset+3].unpack('I')}"
return b[offset..offset+3].unpack('I')[0].to_i
end
0
end
def ip2long(ip)
ip.split('.').inject(0) {|s,x| s*256 + x.to_i}
end
end