mirror of
https://github.com/lionsoul2014/ip2region.git
synced 2025-12-08 19:25:22 +00:00
138 lines
3.5 KiB
C++
138 lines
3.5 KiB
C++
|
|
#include "search.h"
|
|
|
|
namespace xdb {
|
|
|
|
search_t::search_t(const string &file, int version, int p)
|
|
: db(fopen(file.data(), "r")), header(db), policy(p) {
|
|
init_xdb(version);
|
|
|
|
if (db == NULL)
|
|
log_exit("can't open " + file);
|
|
if (header.ip_version() != version)
|
|
log_exit("ip 版本不匹配");
|
|
|
|
if (policy != policy_file) {
|
|
read_bin(length_header, vector, length_vector, db);
|
|
if (policy == policy_content) {
|
|
fseek(db, 0, SEEK_END);
|
|
int size = ftell(db) - length_vector - length_header;
|
|
content = (char *)malloc(size);
|
|
read_bin(length_vector + length_header, content, size, db);
|
|
}
|
|
}
|
|
}
|
|
|
|
search_t::~search_t() {
|
|
fclose(db);
|
|
if (policy == policy_content)
|
|
free(content);
|
|
}
|
|
|
|
int search_t::get_io_count() {
|
|
return io_count;
|
|
}
|
|
|
|
int search_t::get_cost_time() {
|
|
return cost_time;
|
|
}
|
|
|
|
char const *search_t::get_content_index_help(int index) {
|
|
if (policy != policy_file)
|
|
return vector + index;
|
|
|
|
++io_count;
|
|
static char v[8];
|
|
read_bin(length_header + index, v, sizeof(v), db);
|
|
return v;
|
|
}
|
|
|
|
void search_t::get_content_index(const ip_t &ip, int &left, int &right) {
|
|
int index = ((unsigned char)ip.p[0] * 256 + (unsigned char)ip.p[1]) * 8;
|
|
|
|
const char *p = get_content_index_help(index);
|
|
left = to_uint(p);
|
|
right = to_uint(p + 4);
|
|
}
|
|
|
|
char const *search_t::get_content_help(int index) {
|
|
if (policy == policy_content)
|
|
return content + index - length_header - length_vector;
|
|
++io_count;
|
|
static char v[16 + 16 + 2 + 4];
|
|
read_bin(index, v, content_size, db);
|
|
return v;
|
|
}
|
|
|
|
string search_t::get_region(int index, int len) {
|
|
if (policy == policy_content)
|
|
return string(content + index - length_header - length_vector, len);
|
|
++io_count;
|
|
char *p = (char *)malloc(sizeof(char) * len);
|
|
read_bin(index, p, len, db);
|
|
string res(p, len);
|
|
free(p);
|
|
return res;
|
|
}
|
|
|
|
void search_t::get_content(int index,
|
|
ip_t &ip_left,
|
|
ip_t &ip_right,
|
|
int ®ion_len,
|
|
int ®ion_index) {
|
|
const char *p = get_content_help(index);
|
|
|
|
ip_left.from_xdb(p);
|
|
ip_right.from_xdb(p + ip_size);
|
|
|
|
region_len = to_ushort(p + ip_size * 2);
|
|
region_index = to_uint(p + ip_size * 2 + 2);
|
|
}
|
|
|
|
string search_t::search(const ip_t &ip) {
|
|
io_count = 0;
|
|
|
|
int content_left, content_right;
|
|
get_content_index(ip, content_left, content_right);
|
|
|
|
if (content_left == 0 || content_right == 0)
|
|
return "";
|
|
|
|
ip_t ip_left, ip_right;
|
|
int region_len;
|
|
int region_index;
|
|
|
|
int left = 0;
|
|
int right = (content_right - content_left) / content_size;
|
|
|
|
for (;;) {
|
|
int mid = left + (right - left) / 2;
|
|
int mid_index = content_left + mid * content_size;
|
|
get_content(mid_index, ip_left, ip_right, region_len, region_index);
|
|
|
|
// ip ip_left ip_right
|
|
if (ip < ip_left)
|
|
right = mid - 1;
|
|
// ip_left ip_right ip
|
|
else if (ip_right < ip)
|
|
left = mid + 1;
|
|
else
|
|
return get_region(region_index, region_len);
|
|
}
|
|
}
|
|
|
|
string search_t::search(const string &str) {
|
|
unsigned long long t1 = get_time();
|
|
|
|
ip_t ip;
|
|
if (ip.from_str(str) == false)
|
|
return "invalid ipv" + std::to_string(ip_version) + ": " + str;
|
|
string region = search(ip);
|
|
|
|
unsigned long long t2 = get_time();
|
|
cost_time = t2 - t1;
|
|
return region;
|
|
}
|
|
|
|
} // namespace xdb
|