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