-
Notifications
You must be signed in to change notification settings - Fork 73
Expand file tree
/
Copy pathRandomAccessReader.java
More file actions
127 lines (106 loc) · 3.45 KB
/
RandomAccessReader.java
File metadata and controls
127 lines (106 loc) · 3.45 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package net.ipip.ipdb;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import com.alibaba.fastjson.JSONObject;
import sun.misc.Unsafe;
/**
* @author mckuhei
* */
public class RandomAccessReader extends Reader implements Closeable {
private static final Unsafe U = getUnsafe();
private RandomAccessFile handle;
private long baseOffset;
public RandomAccessReader(String file) throws IOException, InvalidDatabaseException {
this(new File(file));
}
public RandomAccessReader(File file) throws IOException, InvalidDatabaseException {
try {
this.fileSize = (int) file.length();
RandomAccessFile handle = this.handle = new RandomAccessFile(file, "r");
int metaLength = handle.readInt();
byte[] metaBytes = new byte[metaLength];
handle.readFully(metaBytes);
String metaString = new String(metaBytes);
MetaData meta = JSONObject.parseObject(metaString, MetaData.class);
this.nodeCount = meta.nodeCount;
this.meta = meta;
this.baseOffset = handle.getFilePointer();
/** for ipv4 */
if (0x01 == (this.meta.IPVersion & 0x01))
{
int node = 0;
for (int i = 0; i < 96 && node < this.nodeCount; i++) {
if (i >= 80) {
node = this.readNode(node, 1);
} else {
node = this.readNode(node, 0);
}
}
this.v4offset = node;
}
} catch (FileNotFoundException e) {
throw e;
} catch (IOException e) {
throw new InvalidDatabaseException(e);
}
}
@Override
int readNode(int node, int index) {
int off = node * 8 + index * 4;
RandomAccessFile handle = this.handle;
try {
synchronized (handle) {
handle.seek(this.baseOffset + off);
return handle.readInt();
}
} catch (IOException e) {
U.throwException(e);
}
throw new InternalError("Should not reach here");
}
@Override
String resolve(int node) throws InvalidDatabaseException {
final int resoloved = node - this.nodeCount + this.nodeCount * 8;
if (resoloved >= this.fileSize) {
throw new InvalidDatabaseException("database resolve error");
}
RandomAccessFile handle = this.handle;
try {
byte[] data;
synchronized (handle) {
handle.seek(this.baseOffset + resoloved);
int size = handle.readUnsignedShort();
if (this.fileSize < (resoloved + 2 + size)) {
throw new InvalidDatabaseException("database resolve error");
}
data = new byte[size];
handle.readFully(data);
}
return new String(data, StandardCharsets.UTF_8);
} catch (IOException e) {
U.throwException(e);
}
throw new InternalError("Should not reach here");
}
private static Unsafe getUnsafe() {
try {
Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
return (Unsafe) f.get(null);
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
throw new InternalError("Unable to get unsafe", e);
}
}
@Override
protected void finalize() {
close();
}
public void close() {
try {
this.handle.close();
} catch (IOException e) {
U.throwException(e);
}
}
}