class IPDB::Reader

Attributes

meta[R]

Public Class Methods

new(name) click to toggle source
# File lib/ipdb/reader.rb, line 8
def initialize(name)
  if name.nil?
    name = "#{__dir__}/ipipfree.ipdb"
  elsif !File.exists?(name)
    raise "You must specify 'database => ...' in your ipip filter (I looked for '#{name}')"
  end

  if !File.readable? name
    raise "ip database is not readable."
  end

  @data = File.read name, encoding: 'ASCII-8BIT'

  meta_len = @data[0 ... 4].unpack('N')[0]
  meta_buf = @data[4 ... 4+meta_len]

  @meta = JSON.parse(meta_buf)

  if @data.length != (4 + meta_len + @meta['total_size'])
    raise "ip database file size error."
  end

  @node_count = @meta['node_count']
  @cache = {}
  @body = @data[4+meta_len ... @data.length]
end

Public Instance Methods

find(ipx, lang) click to toggle source
# File lib/ipdb/reader.rb, line 40
def find(ipx, lang)
  begin
    ipv = IPAddr.new ipx
  rescue => e
    return e.message
  end

  addr = ipv.hton
  node = ipv.ipv4? ? 96 : 0

  idx = 0
  key = addr[0...16]
  val = @cache[key]
  if !val.nil?
    node = val
    idx = 16
  end

  if node < @node_count
    while idx < 128 do
      bin = addr[idx >> 3].unpack("C")[0]
      flag = (1 & (bin >> 7 - (idx % 8)))
      node = self.read_node(node, flag)
      idx += 1
      if idx == 16
        @cache[key] = node
      end
      if node > @node_count
        break
      end
    end
  end

  resolved = node - @node_count + @node_count * 8
  size = @body[resolved..resolved+1].unpack('n')[0]

  temp = @body[resolved+2..resolved+1+size]
  loc = temp.encode("UTF-8", "UTF-8").split("\t", @meta['fields'].length * @meta['languages'].length)

  off = @meta['languages'][lang]

  loc[off ... @meta['fields'].length+off]
end
read_node(node, idx) click to toggle source
# File lib/ipdb/reader.rb, line 35
def read_node(node, idx)
  off = node * 8 + idx * 4
  @body[off..off+3].unpack('N')[0]
end