1
2
3
4
5
6
7
8
9
10
11
12
13
14 package com.sun.jna;
15
16 import java.math.BigInteger;
17 import java.nio.ByteOrder;
18 import java.util.IdentityHashMap;
19 import java.util.Map;
20
21
22
23
24
25 public class BitFields {
26 private static abstract class PrimHandler {
27 abstract long longValue(Object value);
28 abstract Object objectValue(long value);
29 abstract void writeLong(Pointer p, long offset, long value);
30 abstract long readLong(Pointer p, long offset);
31 abstract int size();
32 abstract void writeObject(Pointer pointer, long offset, Object value);
33 abstract Object readObject(Pointer p, long offset);
34 boolean supportsBitOffset() {
35 return true;
36 }
37 boolean supportsBitLength() {
38 return true;
39 }
40 }
41 private static abstract class NonIntHandler extends PrimHandler {
42 public void writeLong(Pointer p, long offset, long value) {
43 throw new UnsupportedOperationException();
44 }
45 public long readLong(Pointer p, long offset) {
46 throw new UnsupportedOperationException();
47 }
48 public Object objectValue(long value) {
49 throw new UnsupportedOperationException();
50 }
51 public long longValue(Object value) {
52 throw new UnsupportedOperationException();
53 }
54 public boolean supportsBitLength() {
55 return false;
56 }
57 }
58 private static final class StringHandler extends NonIntHandler {
59 final boolean wide;
60 public StringHandler(boolean wide) {
61 this.wide = wide;
62 }
63 public Object readObject(Pointer p, long offset) {
64 p = p.getPointer(offset);
65 return p != null ? wide ? (Object)new WString(p.getString(0, true)) : (Object)p.getString(0) : null;
66 }
67 public int size() {
68 return Native.POINTER_SIZE;
69 }
70
71
72 public void writeObject(Pointer pointer, long offset, Object value) {
73 pointer.setPointer(offset, (Pointer)value);
74 }
75
76 }
77 private static final PrimHandler
78 INT_HANDLER = new PrimHandler() {
79 public void writeLong(Pointer p, long offset, long value) {
80 p.setInt(offset, (int)value);
81 }
82 public long readLong(Pointer p, long offset) {
83 return p.getInt(offset);
84 }
85 public Object objectValue(long value) {
86 return new Integer((int)value);
87 }
88 public long longValue(Object value) {
89 return ((Integer)value).longValue();
90 }
91 public void writeObject(Pointer p, long offset, Object value) {
92 p.setInt(offset, value == null ? 0 : ((Integer)value).intValue());
93 }
94 public Object readObject(Pointer p, long offset) {
95 return new Integer(p.getInt(offset));
96 }
97 public int size() {
98 return 4;
99 }
100 },
101 LONG_HANDLER = new PrimHandler() {
102 public void writeLong(Pointer p, long offset, long value) {
103 p.setLong(offset, value);
104 }
105 public long readLong(Pointer p, long offset) {
106 return p.getLong(offset);
107 }
108 public Object objectValue(long value) {
109 return new Long(value);
110 }
111 public long longValue(Object value) {
112 return ((Long)value).longValue();
113 }
114 public void writeObject(Pointer p, long offset, Object value) {
115 p.setLong(offset, value == null ? 0 : ((Long)value).longValue());
116 }
117 public Object readObject(Pointer p, long offset) {
118 return new Long(p.getLong(offset));
119 }
120 public int size() {
121 return 8;
122 }
123 },
124 SHORT_HANDLER = new PrimHandler() {
125 public void writeLong(Pointer p, long offset, long value) {
126 p.setShort(offset, (short)value);
127 }
128 public long readLong(Pointer p, long offset) {
129 return p.getShort(offset);
130 }
131 public Object objectValue(long value) {
132 return new Short((short)value);
133 }
134 public long longValue(Object value) {
135 return ((Short)value).longValue();
136 }
137 public void writeObject(Pointer p, long offset, Object value) {
138 p.setShort(offset, value == null ? 0 : ((Short)value).shortValue());
139 }
140 public Object readObject(Pointer p, long offset) {
141 return new Short(p.getShort(offset));
142 }
143 public int size() {
144 return 2;
145 }
146 },
147 BYTE_HANDLER = new PrimHandler() {
148 public void writeLong(Pointer p, long offset, long value) {
149 p.setByte(offset, (byte)value);
150 }
151 public long readLong(Pointer p, long offset) {
152 return p.getByte(offset);
153 }
154 public Object objectValue(long value) {
155 return new Byte((byte)value);
156 }
157 public long longValue(Object value) {
158 return ((Byte)value).longValue();
159 }
160 public void writeObject(Pointer p, long offset, Object value) {
161 p.setByte(offset, value == null ? 0 : ((Byte)value).byteValue());
162 }
163 public Object readObject(Pointer p, long offset) {
164 return new Byte(p.getByte(offset));
165 }
166 public int size() {
167 return 1;
168 }
169 },
170 CHAR_HANDLER = new PrimHandler() {
171 public void writeLong(Pointer p, long offset, long value) {
172 p.setChar(offset, (char)value);
173 }
174 public long readLong(Pointer p, long offset) {
175 return p.getChar(offset);
176 }
177 public Object objectValue(long value) {
178 return new Character((char)value);
179 }
180 public long longValue(Object value) {
181 return ((Character)value).charValue();
182 }
183 public void writeObject(Pointer p, long offset, Object value) {
184 p.setChar(offset, value == null ? (char)0 : ((Character)value).charValue());
185 }
186 public Object readObject(Pointer p, long offset) {
187 return new Character(p.getChar(offset));
188 }
189 public int size() {
190 return 2;
191 }
192 },
193 BOOL_HANDLER = new PrimHandler() {
194 public void writeLong(Pointer p, long offset, long value) {
195 p.setByte(offset, (byte)value);
196 }
197 public long readLong(Pointer p, long offset) {
198 return p.getByte(offset);
199 }
200 public Object objectValue(long value) {
201 return ((byte)value) == 0 ? Boolean.FALSE : Boolean.TRUE;
202 }
203 public long longValue(Object value) {
204 return ((Boolean)value).booleanValue() ? -1 : 0;
205 }
206 public void writeObject(Pointer p, long offset, Object value) {
207 p.setByte(offset, value == null ? 0 : (byte)(Boolean.TRUE.equals(value) ? -1 : 0));
208 }
209 public Object readObject(Pointer p, long offset) {
210 return p.getByte(offset) == 0 ? Boolean.FALSE : Boolean.TRUE;
211 }
212 public int size() {
213 return 1;
214 }
215 },
216 DOUBLE_HANDLER = new NonIntHandler() {
217 public long readLong(Pointer p, long offset) {
218 return p.getLong(offset);
219 }
220 public void writeLong(Pointer p, long offset, long value) {
221 p.setLong(offset, value);
222 }
223 public long longValue(Object value) {
224 return Double.doubleToRawLongBits(((Double)value).doubleValue());
225 }
226 public Object objectValue(long value) {
227 return new Double(Double.longBitsToDouble((long)value));
228 }
229 public void writeObject(Pointer p, long offset, Object value) {
230 p.setDouble(offset, value == null ? 0 : ((Double)value).doubleValue());
231 }
232 public Object readObject(Pointer p, long offset) {
233 return new Double(p.getDouble(offset));
234 }
235 public int size() {
236 return 8;
237 }
238 },
239 FLOAT_HANDLER = new NonIntHandler() {
240 public long readLong(Pointer p, long offset) {
241 return p.getInt(offset);
242 }
243 public void writeLong(Pointer p, long offset, long value) {
244 p.setInt(offset, (int)value);
245 }
246 public long longValue(Object value) {
247 return Float.floatToRawIntBits(((Float)value).floatValue());
248 }
249 public Object objectValue(long value) {
250 return new Float(Float.intBitsToFloat((int)value));
251 }
252 public void writeObject(Pointer p, long offset, Object value) {
253 p.setFloat(offset, value == null ? 0 : ((Float)value).floatValue());
254 }
255 public Object readObject(Pointer p, long offset) {
256 return new Float(p.getFloat(offset));
257 }
258 public int size() {
259 return 4;
260 }
261 },
262
263
264
265
266
267
268
269
270
271
272
273 STRING_HANDLER = new StringHandler(false),
274 WSTRING_HANDLER = new StringHandler(true)
275 ;
276
277 private static final Map primHandlers = new IdentityHashMap(10);
278 static {
279 primHandlers.put(Integer.TYPE, INT_HANDLER);
280 primHandlers.put(Integer.class, INT_HANDLER);
281
282 primHandlers.put(Long.TYPE, LONG_HANDLER);
283 primHandlers.put(Long.class, LONG_HANDLER);
284
285 primHandlers.put(Short.TYPE, SHORT_HANDLER);
286 primHandlers.put(Short.class, SHORT_HANDLER);
287
288 primHandlers.put(Byte.TYPE, BYTE_HANDLER);
289 primHandlers.put(Byte.class, BYTE_HANDLER);
290
291 primHandlers.put(Character.TYPE, CHAR_HANDLER);
292 primHandlers.put(Character.class, CHAR_HANDLER);
293
294 primHandlers.put(Boolean.TYPE, BOOL_HANDLER);
295 primHandlers.put(Boolean.class, BOOL_HANDLER);
296
297 primHandlers.put(Float.TYPE, FLOAT_HANDLER);
298 primHandlers.put(Float.class, FLOAT_HANDLER);
299
300 primHandlers.put(Double.TYPE, DOUBLE_HANDLER);
301 primHandlers.put(Double.class, DOUBLE_HANDLER);
302
303
304 primHandlers.put(String.class, STRING_HANDLER);
305 primHandlers.put(WString.class, WSTRING_HANDLER);
306 }
307 private static PrimHandler getHandlerWithAtLeastNBytes(final int n) {
308 switch (n) {
309 case 1:
310 return BYTE_HANDLER;
311 case 2:
312 return SHORT_HANDLER;
313 case 3:
314 case 4:
315 return INT_HANDLER;
316 case 5:
317 case 6:
318 case 7:
319 case 8:
320 return LONG_HANDLER;
321 default:
322 return null;
323
324 }
325 }
326
327 private static PrimHandler getPrimHandler(Class type, int bitOffset, int bits) {
328 PrimHandler handler = (PrimHandler)primHandlers.get(type);
329
330
331 if (handler == null && (bitOffset | bits) != 0 ||
332 handler != null && (
333 !handler.supportsBitOffset() && (bitOffset != 0) ||
334 !handler.supportsBitLength() && (bits != 0)
335 )
336 )
337 throw new UnsupportedOperationException("Bit fields only support integral fields !!!");
338
339
340
341 return handler;
342 }
343
344 static void print(BigInteger bi) {
345 for (int i = 0, len = bi.bitLength(); i < len; i++)
346 System.out.print(bi.testBit(i) ? '1' : '0');
347 System.out.println();
348 }
349 private static BigInteger shiftedMask(int bits, int bitOffset) {
350 BigInteger mask = BigInteger.valueOf(bits == 0 ? 0 : 1L);
351 if (bits != 0)
352 mask = mask.shiftLeft(bits);
353 mask = mask.subtract(BigInteger.valueOf(1));
354 if (bitOffset != 0) {
355 mask = mask.shiftLeft(bitOffset);
356
357 for (int i = 0; i < bitOffset; i++)
358 mask.clearBit(i);
359 }
360 return mask;
361 }
362
363 private static byte[] getBigEndianByteArray(Pointer pointer, long offset, int bytesToFetch) {
364 byte[] bs = pointer.getByteArray(offset, bytesToFetch);
365 if (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN)
366 revert(bs);
367 return bs;
368 }
369 private static void setBigEndianByteArray(Pointer pointer, long offset, byte[] bs) {
370 if (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN)
371 revert(bs);
372 pointer.write(offset, bs, 0, bs.length);
373 }
374 private static void revert(byte[] bs) {
375 for (int i = 0, len = bs.length, sup = len >>> 1; i < sup; i++) {
376 int j = len - i - 1;
377
378 byte t = bs[i];
379 bs[i] = bs[j];
380 bs[j] = t;
381 }
382 }
383 public static final Object UNHANDLED_TYPE = new Object() {};
384
385 public static boolean setPrimitiveValue(Pointer pointer, long offset, int bitOffset, int bits, Object value, Class type) {
386 PrimHandler handler = getPrimHandler(type, bitOffset, bits);
387 if (handler == null)
388 return false;
389
390 if ((bitOffset | bits) == 0) {
391 handler.writeObject(pointer, offset, value);
392 return true;
393 }
394
395 if (bits <= 0)
396 bits = handler.size() << 3;
397
398
399
400
401 int bitLen = bits + bitOffset;
402 int bytesToFetch = (bitLen >> 3) + ((bitLen & 7) == 0 ? 0 : 1);
403 PrimHandler io = getHandlerWithAtLeastNBytes(bytesToFetch);
404 if (io != null) {
405 long longValue = handler.longValue(value);
406 longValue <<= bitOffset;
407
408 long existing = io.readLong(pointer, offset);
409 if (bits != 0) {
410 long mask = ((1L << bits) - 1) << bitOffset;
411 longValue &= mask;
412 existing &= ~mask;
413 }
414 longValue |= existing;
415 io.writeLong(pointer, offset, longValue);
416 } else {
417 BigInteger bigValue = BigInteger.valueOf(handler.longValue(value));
418 bigValue = bigValue.shiftLeft(bitOffset);
419
420 byte[] bs = getBigEndianByteArray(pointer, offset, bytesToFetch);
421 BigInteger existing = new BigInteger(bs);
422 BigInteger mask = shiftedMask(bits, bitOffset);
423 bigValue = bigValue.and(mask);
424 existing = existing.and(mask.not());
425 bigValue = bigValue.or(existing);
426
427 setBigEndianByteArray(pointer, offset, bigValue.toByteArray());
428 }
429 return true;
430 }
431 public static Object getPrimitiveValue(Pointer pointer, long offset, int bitOffset, int bits, Class type) {
432 PrimHandler handler = getPrimHandler(type, bitOffset, bits);
433 if (handler == null)
434 return UNHANDLED_TYPE;
435
436 if ((bitOffset | bits) == 0)
437 return handler.readObject(pointer, offset);
438
439 if (bits <= 0)
440 bits = handler.size() << 3;
441
442
443 int bitLen = bits + bitOffset;
444 int bytesToFetch = (bitLen >> 3) + ((bitLen & 7) == 0 ? 0 : 1);
445
446 long longValue;
447 PrimHandler io = getHandlerWithAtLeastNBytes(bytesToFetch);
448 if (io != null) {
449 longValue = io.readLong(pointer, offset);
450 longValue >>= bitOffset;
451 if (bits != 0) {
452 long mask = (1L << bits) - 1;
453 longValue &= mask;
454 }
455 } else {
456 BigInteger bigValue = new BigInteger(getBigEndianByteArray(pointer, offset, bytesToFetch));
457 bigValue = bigValue.shiftRight(bitOffset);
458 if (bits != 0) {
459 BigInteger mask = shiftedMask(bits, 0);
460 bigValue = bigValue.and(mask);
461 }
462 longValue = bigValue.longValue();
463 }
464 return handler.objectValue(longValue);
465 }
466
467
468 }
469