Class: IpLocationCn::QqWry

Inherits:
Object
  • Object
show all
Includes:
Singleton
Defined in:
lib/ip_location_cn/qq_wry.rb

Instance Method Summary collapse

Constructor Details

#initializeQqWry

Returns a new instance of QqWry.



6
7
8
9
10
11
12
# File 'lib/ip_location_cn/qq_wry.rb', line 6

def initialize
  data_file_path = File.expand_path("../../data/qqwry.dat", __FILE__)
  @data_file = File.open data_file_path, 'r'
  @index_first, @index_last = @data_file.read(8).unpack('L2')
  @index_total = (@index_last - @index_first) / 7 + 1
  @location = {}
end

Instance Method Details

#find_ip_location(ip) ⇒ Object

根据IP查找地址



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/ip_location_cn/qq_wry.rb', line 85

def find_ip_location(ip)
  offset = find_str_offset(ip2long(ip))#读取具体数据在记录区的偏移
  @location = {}
  case read_mode(offset + 4)
  when 1
    str_offset = read_offset(offset + 4 + 1) #读取字符串存储位置偏移(4是IP值,1是模式)
    if read_mode(str_offset) == 2 then
      location_offset = read_offset(str_offset+1)
      @location[:location] = read_str location_offset
      @location[:origin] = read_origin(str_offset+4)
    else
      @location[:location] = read_str str_offset
      @location[:origin] = read_origin(@data_file.pos)
    end
  when 2
    str_offset = read_offset(offset + 4 + 1) #读取字符串存储位置偏移(4是IP值,1是模式)
    @location[:location] = read_str(str_offset)
    @location[:origin] = read_origin(offset + 8)
  else
    @location[:location] = read_str(offset)
    @location[:origin] = read_str(@data_file.pos)
  end
  @location
end

#find_str_offset(ip_long) ⇒ Object

根据IP在索引中查找具体位置



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/ip_location_cn/qq_wry.rb', line 46

def find_str_offset(ip_long)
  offset_min, offset_max = @index_first, @index_last
  while offset_min <= offset_max
    offset_mid = offset_min + (offset_max - offset_min) / 14 * 7
    mid = read_long(offset_mid)
    if ip_long < mid
      offset_max = offset_mid - 7
    elsif ip_long == mid
      return read_offset(offset_mid+4)
    else
      offset_min = offset_mid + 7
    end
  end
 
  return read_offset(offset_max + 4)
end

#ip2long(ip) ⇒ Object

把IP转换为长整形



76
77
78
79
80
81
82
# File 'lib/ip_location_cn/qq_wry.rb', line 76

def ip2long(ip)
  long = 0
  ip.split(/\./).each_with_index do |b, i|
    long += b.to_i << 8 * (3 - i)
  end
  long
end

#read_long(position) ⇒ Object

读取记录中的4字节作为一个long值



22
23
24
25
# File 'lib/ip_location_cn/qq_wry.rb', line 22

def read_long(position)
  @data_file.seek position
  @data_file.read(4).unpack('L')[0]
end

#read_mode(position) ⇒ Object

读取模式信息,1和2为正常,其他值异常 position:字符串偏移量



28
29
30
31
# File 'lib/ip_location_cn/qq_wry.rb', line 28

def read_mode(position)
  @data_file.seek position #前4位为IP值
  @data_file.read(1).unpack('C')[0]
end

#read_offset(position) ⇒ Object

读取偏移值



15
16
17
18
19
# File 'lib/ip_location_cn/qq_wry.rb', line 15

def read_offset(position)
  @data_file.seek position
  chars = @data_file.read(3).unpack('C3')
  (chars[2] << 16) + (chars[1] << 8) + chars[0]
end

#read_origin(position) ⇒ Object

读取记录中的地址信息



34
35
36
37
38
39
40
41
42
43
# File 'lib/ip_location_cn/qq_wry.rb', line 34

def read_origin(position)
  mode = read_mode(position)
  if mode == 1 || mode == 2
    offset = read_offset(position + 1)
    return '' if offset == 0
    return read_str(offset)
  else
    return read_str(position)
  end
end

#read_str(position) ⇒ Object

读取字符串



64
65
66
67
68
69
70
71
72
73
# File 'lib/ip_location_cn/qq_wry.rb', line 64

def read_str(position)
  @data_file.seek position
  str = []
  while c = @data_file.getc
    break if str.size > 60 #地址不会太长,防止有异常数据
    break if c == "\0"  #地址字符串以\0结尾
    str << c
  end
  str.join ''
end