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