001 /*
002 * Copyright (c) 2009 Olivier Chafik, All Rights Reserved
003 *
004 * This library is free software; you can redistribute it and/or
005 * modify it under the terms of the GNU Lesser General Public
006 * License as published by the Free Software Foundation; either
007 * version 2.1 of the License, or (at your option) any later version.
008 * <p/>
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 */
014 package com.sun.jna;
015
016 import java.math.BigInteger;
017 import java.nio.ByteOrder;
018 import java.util.IdentityHashMap;
019 import java.util.Map;
020
021 /**
022 * Support for C bit fields
023 * @author Olivier Chafik
024 */
025 public class BitFields {
026 private static abstract class PrimHandler {
027 abstract long longValue(Object value);
028 abstract Object objectValue(long value);
029 abstract void writeLong(Pointer p, long offset, long value);
030 abstract long readLong(Pointer p, long offset);
031 abstract int size();
032 abstract void writeObject(Pointer pointer, long offset, Object value);
033 abstract Object readObject(Pointer p, long offset);
034 boolean supportsBitOffset() {
035 return true;
036 }
037 boolean supportsBitLength() {
038 return true;
039 }
040 }
041 private static abstract class NonIntHandler extends PrimHandler {
042 public void writeLong(Pointer p, long offset, long value) {
043 throw new UnsupportedOperationException();
044 }
045 public long readLong(Pointer p, long offset) {
046 throw new UnsupportedOperationException();
047 }
048 public Object objectValue(long value) {
049 throw new UnsupportedOperationException();
050 }
051 public long longValue(Object value) {
052 throw new UnsupportedOperationException();
053 }
054 public boolean supportsBitLength() {
055 return false;
056 }
057 }
058 private static final class StringHandler extends NonIntHandler {
059 final boolean wide;
060 public StringHandler(boolean wide) {
061 this.wide = wide;
062 }
063 public Object readObject(Pointer p, long offset) {
064 p = p.getPointer(offset);
065 return p != null ? wide ? (Object)new WString(p.getString(0, true)) : (Object)p.getString(0) : null;
066 }
067 public int size() {
068 return Native.POINTER_SIZE;
069 }
070
071
072 public void writeObject(Pointer pointer, long offset, Object value) {
073 pointer.setPointer(offset, (Pointer)value);
074 }
075
076 }
077 private static final PrimHandler
078 INT_HANDLER = new PrimHandler() {
079 public void writeLong(Pointer p, long offset, long value) {
080 p.setInt(offset, (int)value);
081 }
082 public long readLong(Pointer p, long offset) {
083 return p.getInt(offset);
084 }
085 public Object objectValue(long value) {
086 return new Integer((int)value);
087 }
088 public long longValue(Object value) {
089 return ((Integer)value).longValue();
090 }
091 public void writeObject(Pointer p, long offset, Object value) {
092 p.setInt(offset, value == null ? 0 : ((Integer)value).intValue());
093 }
094 public Object readObject(Pointer p, long offset) {
095 return new Integer(p.getInt(offset));
096 }
097 public int size() {
098 return 4;
099 }
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 // POINTER_HANDLER = new NonIntHandler() {
263 // public void writeObject(Pointer p, long offset, Object value) {
264 // p.setPointer(offset, ((Pointer)value));
265 //}
266 //public Object readObject(Pointer p, long offset) {
267 // return p.getPointer(offset);
268 //}
269 //public int size() {
270 // return Native.POINTER_SIZE;
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 // primHandlers.put(Pointer.class, POINTER_HANDLER);
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 //throw new UnsupportedOperationException("TODO No handler for " + n + " bytes !");
324 }
325 }
326
327 private static PrimHandler getPrimHandler(Class type, int bitOffset, int bits) {
328 PrimHandler handler = (PrimHandler)primHandlers.get(type);
329 // if (handler == null && Pointer.class.isAssignableFrom(type))
330 // handler = (PrimHandler)primHandlers.get(Pointer.class);
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 //if ((bits & ~63) != 0)
339 // throw new UnsupportedOperationException("Bit fields cannot be larger than 64 bits !!!");
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 // Fix sign extension :
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 // Read existing alien bits to OR them,
399 // and make sure we read/write bits up to bits + bitOffset
400 // (may need to use larger type than that of the value for read operation)
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 // Read bits to up to bits + bitOffset - 1
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