diff --git a/src/org/jruby/ext/posix/HeapStruct.java b/src/org/jruby/ext/posix/HeapStruct.java index 02530f2..e42fc6e 100644 --- a/src/org/jruby/ext/posix/HeapStruct.java +++ b/src/org/jruby/ext/posix/HeapStruct.java @@ -49,6 +49,7 @@ public class HeapStruct implements com.sun.jna.NativeMapped { */ private static final int LONG_SIZE = (Platform.isWindows() ? 4 : Pointer.SIZE) * 8; private static final int LONG_ALIGN = isSPARC ? 64 : LONG_SIZE; + private static final long LONG_MASK = LONG_SIZE == 32 ? 0x7FFFFFFFL : 0x7FFFFFFFFFFFFFFFL; private static final int DOUBLE_ALIGN = isSPARC ? 64 : LONG_SIZE; private static final int FLOAT_ALIGN = isSPARC ? 64 : 32; private ByteBuffer buffer; @@ -111,6 +112,22 @@ public class HeapStruct implements com.sun.jna.NativeMapped { getByteBuffer().put(offset, value); } } + protected class UInt8 extends Field { + public UInt8() { + super(8); + } + public UInt8(short value) { + this(); + set(value); + } + public final short get() { + final short value = getByteBuffer().get(offset); + return value < 0 ? (short) ((value & 0x7F) + 0x80) : value; + } + public final void set(short value) { + getByteBuffer().put(offset, (byte) value); + } + } protected final class Byte extends Int8 { public Byte() { } public Byte(byte value) { @@ -132,6 +149,22 @@ public class HeapStruct implements com.sun.jna.NativeMapped { getByteBuffer().putShort(offset, value); } } + protected class UInt16 extends Field { + public UInt16() { + super(16); + } + public UInt16(short value) { + this(); + set(value); + } + public final int get() { + final int value = getByteBuffer().getShort(offset); + return value < 0 ? (int)((value & 0x7FFF) + 0x8000) : value; + } + public final void set(int value) { + getByteBuffer().putShort(offset, (short) value); + } + } protected class Short extends Int16 { public Short() {} public Short(short value) { @@ -153,6 +186,22 @@ public class HeapStruct implements com.sun.jna.NativeMapped { getByteBuffer().putInt(offset, value); } } + protected class UInt32 extends Field { + public UInt32() { + super(32); + } + public UInt32(long value) { + this(); + set(value); + } + public final long get() { + final long value = getByteBuffer().getInt(offset); + return value < 0 ? (long)((value & 0x7FFFFFFFL) + 0x80000000L) : value; + } + public final void set(long value) { + getByteBuffer().putInt(offset, (int) value); + } + } protected class Integer extends Int32 { public Integer() {} public Integer(int value) { @@ -195,6 +244,29 @@ public class HeapStruct implements com.sun.jna.NativeMapped { } } } + protected class ULong extends Field { + public ULong() { + super(LONG_SIZE, LONG_ALIGN); + } + public ULong(long value) { + this(); + set(value); + } + public final long get() { + final long value = LONG_SIZE == 32 + ? getByteBuffer().getInt(offset) : getByteBuffer().getLong(offset); + return value < 0 + ? (long) ((value & LONG_MASK) + LONG_MASK + 1) + : value; + } + public final void set(long value) { + if (LONG_SIZE == 32) { + getByteBuffer().putInt(offset, (int) value); + } else { + getByteBuffer().putLong(offset, value); + } + } + } protected class LongLong extends Int64 { public LongLong() { } public LongLong(long value) { diff --git a/test/org/jruby/ext/posix/HeapStructTest.java b/test/org/jruby/ext/posix/HeapStructTest.java new file mode 100644 index 0000000..861ab4e --- /dev/null +++ b/test/org/jruby/ext/posix/HeapStructTest.java @@ -0,0 +1,81 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package org.jruby.ext.posix; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import static org.junit.Assert.*; + +/** + * + */ +public class HeapStructTest { + + public HeapStructTest() { + } + + @BeforeClass + public static void setUpClass() throws Exception { + } + + @AfterClass + public static void tearDownClass() throws Exception { + } + + @Before + public void setUp() { + } + + @After + public void tearDown() { + } + + private static final class Unsigned8Test extends HeapStruct { + public final UInt8 u8 = new UInt8(); + } + @Test + public void unsigned8() { + Unsigned8Test s = new Unsigned8Test(); + final short MAGIC = (short) Byte.MAX_VALUE + 1; + s.u8.set(MAGIC); + assertEquals("Incorrect unsigned byte value", MAGIC, s.u8.get()); + } + private static final class Unsigned16Test extends HeapStruct { + public final UInt16 u16 = new UInt16(); + } + @Test + public void unsigned16() { + Unsigned16Test s = new Unsigned16Test(); + final int MAGIC = (int) Short.MAX_VALUE + 1; + s.u16.set(MAGIC); + assertEquals("Incorrect unsigned short value", MAGIC, s.u16.get()); + } + private static final class Unsigned32Test extends HeapStruct { + public final UInt32 u32 = new UInt32(); + } + @Test + public void unsigned32() { + Unsigned32Test s = new Unsigned32Test(); + final long MAGIC = (long) Integer.MAX_VALUE + 1; + s.u32.set(MAGIC); + assertEquals("Incorrect unsigned int value", MAGIC, s.u32.get()); + } + + + private static final class UnsignedLongTest extends HeapStruct { + public final ULong ul = new ULong(); + } + @Test + public void unsignedLong() { + UnsignedLongTest s = new UnsignedLongTest(); + final long MAGIC = (long) Integer.MAX_VALUE + 1; + s.ul.set(MAGIC); + assertEquals("Incorrect unsigned long value", MAGIC, s.ul.get()); + } +} \ No newline at end of file