View Javadoc

1   /* 
2    * Copyright (c) 2009 Olivier Chafik, All Rights Reserved
3    * 
4    * This library is free software; you can redistribute it and/or
5    * modify it under the terms of the GNU Lesser General Public
6    * License as published by the Free Software Foundation; either
7    * version 2.1 of the License, or (at your option) any later version.
8    * <p/>
9    * This library is distributed in the hope that it will be useful,
10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12   * Lesser General Public License for more details.  
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   * Support for C bit fields
23   * @author Olivier Chafik
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 //	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