mirror of
https://github.com/xiaoqidun/qqwry.git
synced 2026-01-11 08:00:21 +08:00
refactor(重构代码): 重构并保持接口兼容
This commit is contained in:
141
qqwry_dat.go
Normal file
141
qqwry_dat.go
Normal file
@@ -0,0 +1,141 @@
|
||||
package qqwry
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/text/encoding/simplifiedchinese"
|
||||
"golang.org/x/text/transform"
|
||||
)
|
||||
|
||||
const (
|
||||
indexLen = 7
|
||||
redirectMode1 = 0x01
|
||||
redirectMode2 = 0x02
|
||||
)
|
||||
|
||||
// byte3ToUInt32 将3字节切片转换为uint32
|
||||
// 入参: data 3字节切片
|
||||
// 返回: uint32转换后的值
|
||||
func byte3ToUInt32(data []byte) uint32 {
|
||||
i := uint32(data[0]) & 0xff
|
||||
i |= (uint32(data[1]) << 8) & 0xff00
|
||||
i |= (uint32(data[2]) << 16) & 0xff0000
|
||||
return i
|
||||
}
|
||||
|
||||
// gb18030Decode 将GB18030编码解码为UTF-8
|
||||
// 入参: src GB18030编码的字节切片
|
||||
// 返回: string UTF-8编码的字符串
|
||||
func gb18030Decode(src []byte) string {
|
||||
d, _, _ := transform.Bytes(simplifiedchinese.GB18030.NewDecoder(), src)
|
||||
return string(d)
|
||||
}
|
||||
|
||||
// queryIPDat 从DAT数据库查询IP
|
||||
// 入参: ipv4 IPv4地址
|
||||
// 返回: location 位置信息, err 错误信息
|
||||
func (c *Client) queryIPDat(ipv4 string) (location *Location, err error) {
|
||||
ip := net.ParseIP(ipv4).To4()
|
||||
if ip == nil {
|
||||
return nil, errors.New("ip is not ipv4")
|
||||
}
|
||||
ip32 := binary.BigEndian.Uint32(ip)
|
||||
posA := binary.LittleEndian.Uint32(c.data[:4])
|
||||
posZ := binary.LittleEndian.Uint32(c.data[4:8])
|
||||
var offset uint32 = 0
|
||||
for {
|
||||
mid := posA + (((posZ-posA)/indexLen)>>1)*indexLen
|
||||
buf := c.data[mid : mid+indexLen]
|
||||
_ip := binary.LittleEndian.Uint32(buf[:4])
|
||||
if posZ-posA == indexLen {
|
||||
offset = byte3ToUInt32(buf[4:])
|
||||
buf = c.data[mid+indexLen : mid+indexLen+indexLen]
|
||||
if ip32 < binary.LittleEndian.Uint32(buf[:4]) {
|
||||
break
|
||||
} else {
|
||||
offset = 0
|
||||
break
|
||||
}
|
||||
}
|
||||
if _ip > ip32 {
|
||||
posZ = mid
|
||||
} else if _ip < ip32 {
|
||||
posA = mid
|
||||
} else if _ip == ip32 {
|
||||
offset = byte3ToUInt32(buf[4:])
|
||||
break
|
||||
}
|
||||
}
|
||||
if offset <= 0 {
|
||||
return nil, errors.New("ip not found")
|
||||
}
|
||||
posM := offset + 4
|
||||
mode := c.data[posM]
|
||||
var ispPos uint32
|
||||
var addr, isp string
|
||||
switch mode {
|
||||
case redirectMode1:
|
||||
posC := byte3ToUInt32(c.data[posM+1 : posM+4])
|
||||
mode = c.data[posC]
|
||||
posCA := posC
|
||||
if mode == redirectMode2 {
|
||||
posCA = byte3ToUInt32(c.data[posC+1 : posC+4])
|
||||
posC += 4
|
||||
}
|
||||
for i := posCA; i < c.dataLen; i++ {
|
||||
if c.data[i] == 0 {
|
||||
addr = string(c.data[posCA:i])
|
||||
break
|
||||
}
|
||||
}
|
||||
if mode != redirectMode2 {
|
||||
posC += uint32(len(addr) + 1)
|
||||
}
|
||||
ispPos = posC
|
||||
case redirectMode2:
|
||||
posCA := byte3ToUInt32(c.data[posM+1 : posM+4])
|
||||
for i := posCA; i < c.dataLen; i++ {
|
||||
if c.data[i] == 0 {
|
||||
addr = string(c.data[posCA:i])
|
||||
break
|
||||
}
|
||||
}
|
||||
ispPos = offset + 8
|
||||
default:
|
||||
posCA := offset + 4
|
||||
for i := posCA; i < c.dataLen; i++ {
|
||||
if c.data[i] == 0 {
|
||||
addr = string(c.data[posCA:i])
|
||||
break
|
||||
}
|
||||
}
|
||||
ispPos = offset + uint32(5+len(addr))
|
||||
}
|
||||
if addr != "" {
|
||||
addr = strings.TrimSpace(gb18030Decode([]byte(addr)))
|
||||
}
|
||||
ispMode := c.data[ispPos]
|
||||
if ispMode == redirectMode1 || ispMode == redirectMode2 {
|
||||
ispPos = byte3ToUInt32(c.data[ispPos+1 : ispPos+4])
|
||||
}
|
||||
if ispPos > 0 {
|
||||
for i := ispPos; i < c.dataLen; i++ {
|
||||
if c.data[i] == 0 {
|
||||
isp = string(c.data[ispPos:i])
|
||||
if isp != "" {
|
||||
if strings.Contains(isp, "CZ88.NET") {
|
||||
isp = ""
|
||||
} else {
|
||||
isp = strings.TrimSpace(gb18030Decode([]byte(isp)))
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
location = SplitResult(addr, isp, ipv4)
|
||||
return location, nil
|
||||
}
|
||||
Reference in New Issue
Block a user