use std::fs::File;
use std::io::{Read, Seek, SeekFrom};
pub struct QQWry {
pub file:String
}
fn tou32(buf:&mut [u8])->u32{
let b1:u32 = buf[0] as u32 & 0xFF;
let b2:u32 = buf[1] as u32 & 0xFF;
let b3:u32 = buf[2] as u32 & 0xFF;
if buf.len()==4 {
let b4:u32 = buf[3] as u32 & 0xFF;
b4<<24|b3<<16|b2<<8|b1
}else{
b3<<16|b2<<8|b1
}
}
fn ip_to_u32(ip:&str) -> u32{
let k = ip.split(".").enumerate();
let mut buf = vec![];
for (_,item) in k {
let no = item.parse::<u8>().unwrap();
buf.push(no);
}
buf.reverse();
return tou32(&mut buf);
}
fn u32_to_ip(ip:u32)->String{
format!("{}.{}.{}.{}",ip>>24 & 0xFF,ip>>16 & 0xFF,ip>>8 & 0xFF,ip>>0 & 0xFF)
}
fn read_as_string(file: &mut File) -> String{
let mut _b1:[u8;1]=[0];
let mut v: Vec<u8> = Vec::new();
let mut len:u32=0;
loop {
file.read(&mut _b1).expect("read file error");
len=len+1;
if _b1[0]==('\0' as u8) {
break;
}
v.push(_b1[0]);
}
let str = textcode::gb2312::decode_to_string(&v);
return str;
}
fn read_as_area(file: &mut File) -> String{
let mut _b1:[u8;1]=[0];
let mut b3:[u8;3]=[0;3];
file.read(&mut _b1).expect("read file error");
if _b1[0] == 0x01 || _b1[0] == 0x02 {
file.read(&mut b3).expect("error");
let data_offset = tou32(&mut b3);
if data_offset == 0 {
return String::from("unknown.area");
}
file.seek(SeekFrom::Start(data_offset as u64)).expect("read file error");
return read_as_string(file);
}else{
file.seek(SeekFrom::Current(-1)).expect("read file error");
return read_as_string(file);
}
}
fn read_location(file:&mut File, record_offset: &mut u32) ->IPLocation {
let mut location:IPLocation = IPLocation {
index_offset: 0,
start_ip:0,
end_ip: 0,
record_offset: *record_offset,
country: String::from(""),
area: String::from("")
};
let mut b4:[u8;4]=[0;4];
let mut b3:[u8;3]=[0;3];
let mut _b1:[u8;1]=[0];
file.seek(SeekFrom::Start(*record_offset as u64)).expect("read file error");
file.read(&mut b4).expect("read file error");
location.end_ip = tou32(&mut b4);
file.read(&mut _b1).expect("read file error");
if _b1[0] == 0x01 || _b1[0] == 0x02{
file.read(&mut b3).expect("read file error");
let data_offset = tou32(&mut b3);
file.seek(SeekFrom::Start(data_offset as u64)).expect("read file error");
if _b1[0] == 0x01 {
file.read(&mut _b1).expect("read file error");
let area_offset:u64;
if _b1[0] == 0x02 {
area_offset = (data_offset+4) as u64;
file.read(&mut b3).expect("read file error");
let data_offset = tou32(&mut b3);
file.seek(SeekFrom::Start(data_offset as u64)).expect("read file error");
location.country = read_as_string(file);
}else{
file.seek(SeekFrom::Current(-1)).expect("read file error");
location.country = read_as_string(file);
area_offset = file.stream_position().unwrap();
}
file.seek(SeekFrom::Start(area_offset)).expect("read file error");
location.area = read_as_area(file);
} else {
location.country = read_as_string(file);
location.area = read_as_area(file);
}
}else{
file.seek(SeekFrom::Current(-1)).expect("read file error");
location.country = read_as_string(file);
location.area = read_as_area(file);
}
location
}
#[derive(Debug)]
pub struct IPLocation {
pub index_offset: u32,
pub record_offset: u32,
pub start_ip: u32,
pub end_ip:u32,
pub country: String,
pub area:String
}
impl IPLocation {
pub fn get_start_ip_str(&self)->String{
u32_to_ip(self.start_ip)
}
pub fn get_end_ip_str(&self)->String{
u32_to_ip(self.end_ip)
}
}
impl QQWry {
pub fn from(file: String) -> QQWry {
QQWry {
file
}
}
pub fn read_ip_location(&mut self,ip: &str) -> Option<IPLocation> {
let ip = ip_to_u32(ip);
let mut file = File::open(&mut self.file).unwrap();
let mut b4:[u8;4]=[0,0,0,0];
let mut b3:[u8;3]=[0,0,0];
let mut _b1:[u8;1]=[0];
file.read(&mut b4).unwrap();
let first_index_offset:u32 = tou32(&mut b4);
file.read(&mut b4).unwrap();
let last_index_offset:u32 = tou32(&mut b4);
let total_index_records = (last_index_offset-first_index_offset)/7+1;
let mut i:u32=0;
let mut right_edge = false;
let mut result: Option<IPLocation> = None;
loop {
let index_offset = first_index_offset+i*7;
file.seek(SeekFrom::Start(index_offset as u64)).expect("read file error");
file.read(&mut b4).expect("read file error");
file.read(&mut b3).expect("read file error");
let start_ip = tou32(&mut b4);
if ip == start_ip {
let mut record_idx = tou32(&mut b3);
let mut location = read_location(&mut file, &mut record_idx);
location.index_offset = index_offset;
location.start_ip = start_ip;
result = Some(location);
break;
}
if right_edge || (i+1 == total_index_records) {
let mut record_idx = tou32(&mut b3);
let mut location = read_location(&mut file, &mut record_idx);
if ip<=location.end_ip {
location.index_offset = index_offset;
location.start_ip = start_ip;
result = Some(location);
}
break;
}
if ip < start_ip {
i-=1;
right_edge = true;
continue;
}
i = i+1;
}
return result
}
}