Skip to content

Commit 6b0462d

Browse files
committed
make unsafe etc. adhere to an interface
1 parent 47e780d commit 6b0462d

File tree

5 files changed

+195
-156
lines changed

5 files changed

+195
-156
lines changed

src/main/java/bwapi/Client.java

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ of this software and associated documentation files (the "Software"), to deal
2828
import bwapi.ClientData.Command;
2929
import bwapi.ClientData.GameData;
3030
import bwapi.ClientData.Shape;
31+
import bwapi.MemoryAccesses.MemoryAccess;
32+
import bwapi.MemoryAccesses.UnsafeAccess;
33+
import bwapi.MemoryAccesses.DirectBufferAccess;
3134
import com.sun.jna.Native;
3235
import com.sun.jna.platform.win32.Kernel32;
3336
import com.sun.jna.win32.W32APIOptions;
@@ -80,10 +83,20 @@ private void connect(final int procID) throws Exception {
8083
code = pipe.readByte();
8184
}
8285

83-
final ByteBuffer sharedMemory = Kernel32.INSTANCE.MapViewOfFile(MappingKernel.INSTANCE
86+
final ByteBuffer buffer = Kernel32.INSTANCE.MapViewOfFile(MappingKernel.INSTANCE
8487
.OpenFileMapping(READ_WRITE, false, "Local\\bwapi_shared_memory_" + procID), READ_WRITE,
8588
0, 0, GameData.SIZE).getByteBuffer(0, GameData.SIZE);
86-
data = new ClientData(sharedMemory).new GameData(0);
89+
90+
MemoryAccess memoryAccess;
91+
try {
92+
memoryAccess = new UnsafeAccess(buffer);
93+
}
94+
catch (final Exception e) {
95+
System.err.println(e.getMessage());
96+
memoryAccess = new DirectBufferAccess(buffer);
97+
}
98+
99+
data = new ClientData(memoryAccess).new GameData(0);
87100

88101
final int clientVersion = data.getClient_version();
89102
if (clientVersion != BWAPI_VERSION) {

src/main/java/bwapi/ClientData.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
package bwapi;
2-
import java.nio.ByteBuffer;
2+
import bwapi.MemoryAccesses.MemoryAccess;
3+
34
final class ClientData {
4-
private final WrappedBuffer buffer;
5-
ClientData(final ByteBuffer buffer) {
6-
this.buffer = new WrappedBuffer(buffer);
5+
private final MemoryAccess buffer;
6+
ClientData(final MemoryAccess buffer) {
7+
this.buffer = buffer;
78
}
89
class UnitCommand {
910
static final int SIZE = 24;
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
package bwapi;
2+
3+
import sun.misc.Unsafe;
4+
import sun.nio.ch.DirectBuffer;
5+
6+
import java.lang.reflect.Field;
7+
import java.nio.ByteBuffer;
8+
import java.nio.CharBuffer;
9+
import java.nio.charset.Charset;
10+
import java.nio.charset.CharsetEncoder;
11+
import java.nio.charset.StandardCharsets;
12+
13+
class MemoryAccesses {
14+
private static final Charset charSet = StandardCharsets.ISO_8859_1;
15+
private static final CharsetEncoder enc = charSet.newEncoder();
16+
17+
private static String asString(final byte[] buf, final int maxLen) {
18+
int len = 0;
19+
while (len < maxLen && buf[len] != 0) {
20+
++len;
21+
}
22+
return new String(buf, 0, len, charSet);
23+
}
24+
private static void setString(final ByteBuffer buffer, final int offset, final int maxLen, final String string) {
25+
if (string.length() + 1 >= maxLen) {
26+
throw new StringIndexOutOfBoundsException();
27+
}
28+
buffer.position(offset);
29+
enc.encode(CharBuffer.wrap(string), buffer, true);
30+
buffer.put((byte) 0);
31+
}
32+
33+
interface MemoryAccess {
34+
35+
byte getByte(int offset);
36+
37+
void putByte(int offset, byte value);
38+
39+
short getShort(int offset);
40+
41+
void putShort(int offset, short value);
42+
43+
int getInt(int offset);
44+
45+
void putInt(int offset, final int value);
46+
47+
double getDouble(int offset);
48+
49+
void putDouble(int offset, final double value);
50+
51+
String getString(int offset, final int maxLen);
52+
53+
void putString(int offset, final int maxLen, final String string);
54+
}
55+
56+
/**
57+
* Wrapper around ByteBuffer that makes use of sun.misc.Unsafe
58+
*/
59+
static class UnsafeAccess implements MemoryAccess {
60+
61+
private final ByteBuffer buffer;
62+
private final long address;
63+
private final Unsafe unsafe;
64+
65+
UnsafeAccess(final ByteBuffer byteBuffer) throws NoSuchFieldException, IllegalAccessException {
66+
final Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
67+
theUnsafe.setAccessible(true);
68+
69+
unsafe = (Unsafe) theUnsafe.get(null);
70+
buffer = byteBuffer;
71+
address = ((DirectBuffer) buffer).address();
72+
}
73+
74+
public byte getByte(int offset) {
75+
return unsafe.getByte(address + offset);
76+
}
77+
78+
public void putByte(int offset, byte value) {
79+
unsafe.putByte(address + offset, value);
80+
}
81+
82+
public short getShort(int offset) {
83+
return unsafe.getShort(address + offset);
84+
}
85+
86+
public void putShort(int offset, short value) {
87+
unsafe.putShort(address + offset, value);
88+
}
89+
90+
public int getInt(int offset) {
91+
return unsafe.getInt(address + offset);
92+
}
93+
94+
public void putInt(int offset, int value) {
95+
unsafe.putInt(address + offset, value);
96+
}
97+
98+
public double getDouble(int offset) {
99+
return unsafe.getDouble(address + offset);
100+
}
101+
102+
public void putDouble(int offset, double value) {
103+
unsafe.putDouble(address + offset, value);
104+
}
105+
106+
public String getString(int offset, int maxLen) {
107+
final byte[] buf = new byte[maxLen];
108+
unsafe.copyMemory(null, address + offset, buf, Unsafe.ARRAY_BYTE_BASE_OFFSET, maxLen);
109+
return asString(buf, maxLen);
110+
}
111+
112+
public void putString(int offset, int maxLen, String string) {
113+
setString(buffer, offset, maxLen, string);
114+
}
115+
}
116+
117+
static class DirectBufferAccess implements MemoryAccess {
118+
private final ByteBuffer buffer;
119+
120+
DirectBufferAccess(final ByteBuffer buffer) {
121+
this.buffer = buffer;
122+
}
123+
public byte getByte(int offset) {
124+
return buffer.get(offset);
125+
}
126+
127+
public void putByte(int offset, byte value) {
128+
buffer.put(offset, value);
129+
}
130+
131+
public short getShort(int offset) {
132+
return buffer.getShort(offset);
133+
}
134+
135+
public void putShort(int offset, short value) {
136+
buffer.putShort(offset, value);
137+
}
138+
139+
public int getInt(int offset) {
140+
return buffer.getInt(offset);
141+
}
142+
143+
@Override
144+
public void putInt(int offset, int value) {
145+
buffer.putInt(offset, value);
146+
}
147+
148+
@Override
149+
public double getDouble(int offset) {
150+
return buffer.getDouble(offset);
151+
}
152+
153+
@Override
154+
public void putDouble(int offset, double value) {
155+
buffer.putDouble(offset, value);
156+
}
157+
158+
@Override
159+
public String getString(int offset, int maxLen) {
160+
final byte[] buf = new byte[maxLen];
161+
buffer.position(offset);
162+
buffer.get(buf, 0, maxLen);
163+
return null;
164+
}
165+
166+
@Override
167+
public void putString(int offset, int maxLen, String string) {
168+
setString(buffer, offset, maxLen, string);
169+
}
170+
}
171+
}

src/main/java/bwapi/WrappedBuffer.java

Lines changed: 0 additions & 146 deletions
This file was deleted.

src/test/java/DumpToClient.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,11 +90,11 @@ public static void main(String[] args) throws IOException {
9090
StringWriter sw = new StringWriter();
9191
try (PrintWriter out = new PrintWriter(sw)) {
9292
out.println("package bwapi;");
93-
out.println("import java.nio.ByteBuffer;");
93+
out.println("import bwapi.MemoryAccesses.MemoryAccess;\n");
9494
out.println("final class ClientData {");
95-
out.println(" private final WrappedBuffer buffer;");
96-
out.println(" ClientData(final ByteBuffer buffer) {");
97-
out.println(" this.buffer = new WrappedBuffer(buffer);");
95+
out.println(" private final MemoryAccess buffer;");
96+
out.println(" ClientData(final MemoryAccess buffer) {");
97+
out.println(" this.buffer = buffer;");
9898
out.println(" }");
9999
structs.values().forEach(s -> {
100100
out.printf(" class %s {\n", s.name);

0 commit comments

Comments
 (0)