diff --git a/CHANGES.md b/CHANGES.md index d0a9e6b5e3..48d2928f1d 100755 --- a/CHANGES.md +++ b/CHANGES.md @@ -50,6 +50,7 @@ Features * [#436] (https://github.com/twall/jna/pull/469): Added basic Pdh API implementation to 'com.sun.jna.platform.win32' - [@lgoldstein](https://github.com/lgoldstein). * [#481] (https://github.com/twall/jna/pull/481): Added volume management functions to 'com.sun.jna.platform.win32' - [@lgoldstein](https://github.com/lgoldstein). * [#483] (https://github.com/twall/jna/pull/483): Found and fixed duplicate method definitions for the same API in 'com.sun.jna.platform.win32' - [@lgoldstein](https://github.com/lgoldstein). +* [#485] (https://github.com/twall/jna/pull/485): Implemented Comparable interface for many of the base types in 'com.sun.jna.platform.win32.WinDef' - [@lgoldstein](https://github.com/lgoldstein). Bug Fixes --------- diff --git a/contrib/platform/src/com/sun/jna/platform/win32/WinDef.java b/contrib/platform/src/com/sun/jna/platform/win32/WinDef.java index 9ef1361032..f2f99a2075 100644 --- a/contrib/platform/src/com/sun/jna/platform/win32/WinDef.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/WinDef.java @@ -41,7 +41,7 @@ public interface WinDef extends StdCallLibrary { /** * 16-bit unsigned integer. */ - public static class WORD extends IntegerType { + public static class WORD extends IntegerType implements Comparable { /** The Constant SIZE. */ public static final int SIZE = 2; @@ -62,6 +62,11 @@ public WORD() { public WORD(long value) { super(SIZE, value, true); } + + @Override + public int compareTo(WORD other) { + return compare(this, other); + } } /** @@ -108,7 +113,7 @@ public WORD getValue() { /** * 32-bit unsigned integer. */ - public static class DWORD extends IntegerType { + public static class DWORD extends IntegerType implements Comparable { /** The Constant SIZE. */ public static final int SIZE = 4; @@ -147,6 +152,11 @@ public WORD getLow() { public WORD getHigh() { return new WORD((longValue() >> 16) & 0xFF); } + + @Override + public int compareTo(DWORD other) { + return compare(this, other); + } } /** @@ -193,7 +203,7 @@ public DWORD getValue() { /** * The Class LONG. */ - public static class LONG extends IntegerType { + public static class LONG extends IntegerType implements Comparable { /** The Constant SIZE. */ public static final int SIZE = Native.LONG_SIZE; @@ -213,6 +223,11 @@ public LONG() { public LONG(long value) { super(SIZE, value); } + + @Override + public int compareTo(LONG other) { + return compare(this, other); + } } /** @@ -259,7 +274,7 @@ public LONG getValue() { /** * The Class LONGLONG. */ - public static class LONGLONG extends IntegerType { + public static class LONGLONG extends IntegerType implements Comparable { /** The Constant SIZE. */ public static final int SIZE = Native.LONG_SIZE *2; @@ -279,6 +294,11 @@ public LONGLONG() { public LONGLONG(long value) { super(8, value, false); } + + @Override + public int compareTo(LONGLONG other) { + return compare(this, other); + } } /** @@ -749,15 +769,9 @@ public class RECT extends Structure { /** The bottom. */ public int bottom; - /* - * (non-Javadoc) - * - * @see com.sun.jna.Structure#getFieldOrder() - */ @Override - protected List getFieldOrder() { - return Arrays.asList(new String[] { "left", "top", "right", - "bottom" }); + protected List getFieldOrder() { + return Arrays.asList("left", "top", "right", "bottom"); } /** @@ -769,11 +783,6 @@ public Rectangle toRectangle() { return new Rectangle(left, top, right - left, bottom - top); } - /* - * (non-Javadoc) - * - * @see com.sun.jna.Structure#toString() - */ @Override public String toString() { return "[(" + left + "," + top + ")(" + right + "," + bottom + ")]"; @@ -783,7 +792,7 @@ public String toString() { /** * 32-bit unsigned integer. */ - public static class ULONG extends IntegerType { + public static class ULONG extends IntegerType implements Comparable { /** The Constant SIZE. */ public static final int SIZE = Native.LONG_SIZE; @@ -801,9 +810,14 @@ public ULONG() { * @param value * the value */ - public ULONG(int value) { + public ULONG(long value) { super(SIZE, value, true); } + + @Override + public int compareTo(ULONG other) { + return compare(this, other); + } } /** @@ -850,7 +864,7 @@ public ULONG getValue() { /** * The Class ULONGLONG. */ - public static class ULONGLONG extends IntegerType { + public static class ULONGLONG extends IntegerType implements Comparable { /** The Constant SIZE. */ public static final int SIZE = Native.LONG_SIZE *2; @@ -870,6 +884,11 @@ public ULONGLONG() { public ULONGLONG(long value) { super(SIZE, value, true); } + + @Override + public int compareTo(ULONGLONG other) { + return compare(this, other); + } } /** @@ -916,7 +935,7 @@ public ULONGLONG getValue() { /** * 64-bit unsigned integer. */ - public static class DWORDLONG extends IntegerType { + public static class DWORDLONG extends IntegerType implements Comparable { /** The Constant SIZE. */ public static final int SIZE = 8; @@ -937,6 +956,11 @@ public DWORDLONG() { public DWORDLONG(long value) { super(SIZE, value, true); } + + @Override + public int compareTo(DWORDLONG other) { + return compare(this, other); + } } /** @@ -1070,21 +1094,16 @@ public POINT(int x, int y) { this.y = y; } - /* - * (non-Javadoc) - * - * @see com.sun.jna.Structure#getFieldOrder() - */ @Override - protected List getFieldOrder() { - return Arrays.asList(new String[] { "x", "y" }); + protected List getFieldOrder() { + return Arrays.asList("x", "y"); } } /** * 16-bit unsigned short. */ - public static class USHORT extends IntegerType { + public static class USHORT extends IntegerType implements Comparable { /** The Constant SIZE. */ public static final int SIZE = 2; @@ -1105,6 +1124,11 @@ public USHORT() { public USHORT(long value) { super(SIZE, value, true); } + + @Override + public int compareTo(USHORT other) { + return compare(this, other); + } } /** @@ -1161,7 +1185,7 @@ public USHORT getValue() { /** * 16-bit short. */ - public static class SHORT extends IntegerType { + public static class SHORT extends IntegerType implements Comparable { /** The Constant SIZE. */ public static final int SIZE = 2; @@ -1182,12 +1206,17 @@ public SHORT() { public SHORT(long value) { super(SIZE, value, false); } + + @Override + public int compareTo(SHORT other) { + return compare(this, other); + } } /** * 32-bit unsigned int. */ - public static class UINT extends IntegerType { + public static class UINT extends IntegerType implements Comparable { /** The Constant SIZE. */ public static final int SIZE = 4; @@ -1208,6 +1237,11 @@ public UINT() { public UINT(long value) { super(SIZE, value, true); } + + @Override + public int compareTo(UINT other) { + return compare(this, other); + } } /** @@ -1269,7 +1303,7 @@ public SCODE() { * @param value * the value */ - public SCODE(int value) { + public SCODE(long value) { super(value); } } @@ -1340,7 +1374,7 @@ public LCID(long value) { /** * The Class BOOL. */ - public static class BOOL extends IntegerType { + public static class BOOL extends IntegerType implements Comparable { /** The Constant SIZE. */ public static final int SIZE = 4; @@ -1352,6 +1386,15 @@ public BOOL() { this(0); } + /** + * Instantiates a new bool. + * + * @param value the value + */ + public BOOL(boolean value) { + this(value ? 1L : 0L); + } + /** * Instantiates a new bool. * @@ -1362,10 +1405,76 @@ public BOOL(long value) { } public boolean booleanValue() { - if(this.intValue() > 0) + if (this.intValue() > 0) { return true; - else + } else { return false; + } + } + + @Override + public String toString() { + return Boolean.toString(booleanValue()); + } + + @Override + public int compareTo(BOOL other) { + return compare(this, other); + } + + /** + * Compares 2 BOOL values - - Note: a {@code null} + * value is considered greater than any non-{@code null} one + * (i.e., {@code null} values are "pushed" to the end + * of a sorted array / list of values) + * + * @param v1 The 1st value + * @param v2 The 2nd value + * @return 0 if values are equal (including if both are {@code null}, + * negative if 1st value less than 2nd one, positive otherwise. Note: + * the comparison uses the {@link #booleanValue()}. + * @see #compare(boolean, boolean) + */ + public static int compare(BOOL v1, BOOL v2) { + if (v1 == v2) { + return 0; + } else if (v1 == null) { + return 1; // v2 cannot be null or v1 == v2 would hold + } else if (v2 == null) { + return (-1); + } else { + return compare(v1.booleanValue(), v2.booleanValue()); + } + } + + /** + * Compares a BOOL value with a {@code long} one. Note: if + * the BOOL value is {@code null} then it is consider greater + * than any {@code long} value. + * + * @param v1 The {@link BOOL} value + * @param v2 The {@code boolean} value + * @return 0 if values are equal, negative if 1st value less than 2nd one, + * positive otherwise. Note: the comparison uses the {@link #longValue()}. + * @see #compare(boolean, boolean) + */ + public static int compare(BOOL v1, boolean v2) { + if (v1 == null) { + return 1; + } else { + return compare(v1.booleanValue(), v2); + } + } + + // TODO when JDK 1.7 becomes the min. version, use Boolean.compare(...) + public static int compare(boolean v1, boolean v2) { + if (v1 == v2) { + return 0; + } else if (v1) { + return 1; // v2 cannot be true or v1 == v2 + } else { + return (-1); + } } } @@ -1413,7 +1522,7 @@ public BOOL getValue() { /** * The Class UCHAR. */ - public static class UCHAR extends IntegerType { + public static class UCHAR extends IntegerType implements Comparable { /** The Constant SIZE. */ public static final int SIZE = 1; @@ -1425,6 +1534,10 @@ public UCHAR() { this(0); } + public UCHAR(char ch) { + this(ch & 0xFF); + } + /** * Instantiates a new uchar. * @@ -1433,6 +1546,11 @@ public UCHAR() { public UCHAR(long value) { super(SIZE, value, true); } + + @Override + public int compareTo(UCHAR other) { + return compare(this, other); + } } /** @@ -1460,7 +1578,7 @@ public BYTE(long value) { /** * The Class CHAR. */ - public static class CHAR extends IntegerType { + public static class CHAR extends IntegerType implements Comparable { /** The Constant SIZE. */ public static final int SIZE = 1; @@ -1472,6 +1590,15 @@ public CHAR() { this(0); } + /** + * Instantiates a new char. + * + * @param ch The {@code char} value + */ + public CHAR(char ch) { + this(ch & 0xFF); + } + /** * Instantiates a new char. * @@ -1480,6 +1607,11 @@ public CHAR() { public CHAR(long value) { super(1, value, false); } + + @Override + public int compareTo(CHAR other) { + return compare(this, other); + } } /** @@ -1568,7 +1700,4 @@ public HGLRCByReference(HGLRC h) { super(h); } } - - - } diff --git a/contrib/platform/src/com/sun/jna/platform/win32/WinNT.java b/contrib/platform/src/com/sun/jna/platform/win32/WinNT.java index 382750af2f..d096f08a07 100644 --- a/contrib/platform/src/com/sun/jna/platform/win32/WinNT.java +++ b/contrib/platform/src/com/sun/jna/platform/win32/WinNT.java @@ -14,9 +14,11 @@ import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.List; import com.sun.jna.FromNativeContext; +import com.sun.jna.IntegerType; import com.sun.jna.Memory; import com.sun.jna.NativeLong; import com.sun.jna.Pointer; @@ -25,9 +27,6 @@ import com.sun.jna.Union; import com.sun.jna.ptr.ByReference; -import com.sun.jna.platform.win32.WinNT.SYSTEM_LOGICAL_PROCESSOR_INFORMATION; -import com.sun.jna.platform.win32.WinNT.LOGICAL_PROCESSOR_RELATIONSHIP; - /** * This module defines the 32-Bit Windows types and constants that are defined * by NT, but exposed through the Win32 API. Ported from WinNT.h Microsoft @@ -251,6 +250,7 @@ public static class LUID_AND_ATTRIBUTES extends Structure { */ public DWORD Attributes; + @Override protected List getFieldOrder() { return Arrays.asList(new String[] { "Luid", "Attributes" }); } @@ -270,6 +270,7 @@ public LUID_AND_ATTRIBUTES(LUID luid, DWORD attributes) { */ public static class SID_AND_ATTRIBUTES extends Structure { + @Override protected List getFieldOrder() { return Arrays.asList(new String[] { "Sid", "Attributes" }); } @@ -300,6 +301,7 @@ public SID_AND_ATTRIBUTES(Pointer memory) { */ public static class TOKEN_OWNER extends Structure { + @Override protected List getFieldOrder() { return Arrays.asList(new String[] { "Owner" }); } @@ -328,6 +330,7 @@ public TOKEN_OWNER(Pointer memory) { public static class PSID extends Structure { public static class ByReference extends PSID implements Structure.ByReference { } + @Override protected List getFieldOrder() { return Arrays.asList(new String[] { "sid" }); } @@ -355,10 +358,10 @@ public byte[] getBytes() { int len = Advapi32.INSTANCE.GetLengthSid(this); return getPointer().getByteArray(0, len); } - + public String getSidString() { return Advapi32Util.convertSidToStringSid(this); - } + } public Pointer sid; } @@ -394,6 +397,7 @@ public PSID getValue() { */ public static class TOKEN_USER extends Structure { + @Override protected List getFieldOrder() { return Arrays.asList(new String[] { "User" }); } @@ -425,6 +429,7 @@ public TOKEN_USER(int size) { */ public static class TOKEN_GROUPS extends Structure { + @Override protected List getFieldOrder() { return Arrays.asList(new String[] { "GroupCount", "Group0" }); } @@ -513,6 +518,7 @@ public static class TOKEN_PRIVILEGES extends Structure { */ public LUID_AND_ATTRIBUTES Privileges[]; + @Override protected List getFieldOrder() { return Arrays.asList(new String[] { "PrivilegeCount", "Privileges" }); } @@ -728,7 +734,7 @@ public abstract class SID_NAME_USE { int FILE_SUPPORTS_OPEN_BY_FILE_ID = 0x01000000; int FILE_SUPPORTS_USN_JOURNAL = 0x02000000; - + // The controllable aspects of the DefineDosDevice function. // see https://msdn.microsoft.com/en-us/library/windows/desktop/aa363904(v=vs.85).aspx int DDD_RAW_TARGET_PATH = 0x00000001; @@ -751,6 +757,7 @@ public static class FILE_NOTIFY_INFORMATION extends Structure { // filename is not nul-terminated, so we can't use a String/WString public char[] FileName = new char[1]; + @Override protected List getFieldOrder() { return Arrays.asList(new String[] { "NextEntryOffset", "Action", "FileNameLength", "FileName" }); } @@ -774,6 +781,7 @@ public String getFilename() { return new String(FileName, 0, FileNameLength / 2); } + @Override public void read() { // avoid reading filename until we know how long it is FileName = new char[0]; @@ -1027,6 +1035,8 @@ public FILE_NOTIFY_INFORMATION next() { public static class LUID extends Structure { public int LowPart; public int HighPart; + + @Override protected List getFieldOrder() { return Arrays.asList(new String[] { "LowPart", "HighPart" }); } @@ -1035,7 +1045,7 @@ protected List getFieldOrder() { /** * A 64-bit integer; */ - public static class LARGE_INTEGER extends Structure { + public static class LARGE_INTEGER extends Structure implements Comparable { public static class ByReference extends LARGE_INTEGER implements Structure.ByReference { } @@ -1043,26 +1053,83 @@ public static class ByReference extends LARGE_INTEGER implements public static class LowHigh extends Structure { public DWORD LowPart; public DWORD HighPart; - protected List getFieldOrder() { - return Arrays.asList(new String[] { "LowPart", "HighPart" }); + + public LowHigh() { + super(); + } + + public LowHigh(long value) { + this(new DWORD(value & 0xFFFFFFFFL), new DWORD((value >> 32) & 0xFFFFFFFFL)); + } + + public LowHigh(DWORD low, DWORD high) { + LowPart = low; + HighPart = high; + } + + @Override + protected List getFieldOrder() { + return Arrays.asList("LowPart", "HighPart"); + } + + public long longValue() { + long loValue = LowPart.longValue(); + long hiValue = HighPart.longValue(); + return ((hiValue << 32) & 0xFFFFFFFF00000000L) | (loValue & 0xFFFFFFFFL); + } + + @Override + public String toString() { + if ((LowPart == null) || (HighPart == null)) { + return "null"; + } else { + return Long.toString(longValue()); + } } } public static class UNION extends Union { public LowHigh lh; public long value; + + public UNION() { + super(); + } + + public UNION(long value) { + this.value = value; + this.lh = new LowHigh(value); + } + + public long longValue() { + return value; + } + + @Override + public String toString() { + return Long.toString(longValue()); + } } public UNION u; - protected List getFieldOrder() { - return Arrays.asList(new String[] { "u" }); + @Override + protected List getFieldOrder() { + return Collections.singletonList("u"); + } + + public LARGE_INTEGER() { + super(); + } + + public LARGE_INTEGER(long value) { + this.u = new UNION(value); } /** * Low DWORD. * - * @return DWORD. + * @return Low DWORD value */ public DWORD getLow() { return u.lh.LowPart; @@ -1071,7 +1138,7 @@ public DWORD getLow() { /** * High DWORD. * - * @return DWORD. + * @return High DWORD value */ public DWORD getHigh() { return u.lh.HighPart; @@ -1080,11 +1147,65 @@ public DWORD getHigh() { /** * 64-bit value. * - * @return 64-bit value. + * @return The 64-bit value. */ public long getValue() { return u.value; } + + @Override + public int compareTo(LARGE_INTEGER other) { + return compare(this, other); + } + + @Override + public String toString() { + return (u == null) ? "null" : Long.toString(getValue()); + } + + /** + * Compares 2 LARGE_INTEGER values - - Note: a {@code null} + * value is considered greater than any non-{@code null} one + * (i.e., {@code null} values are "pushed" to the end + * of a sorted array / list of values) + * + * @param v1 The 1st value + * @param v2 The 2nd value + * @return 0 if values are equal (including if both are {@code null}, + * negative if 1st value less than 2nd one, positive otherwise. Note: + * the comparison uses the {@link #getValue()}. + * @see IntegerType#compare(long, long) + */ + public static int compare(LARGE_INTEGER v1, LARGE_INTEGER v2) { + if (v1 == v2) { + return 0; + } else if (v1 == null) { + return 1; // v2 cannot be null or v1 == v2 would hold + } else if (v2 == null) { + return (-1); + } else { + return IntegerType.compare(v1.getValue(), v2.getValue()); + } + } + + /** + * Compares a LARGE_INTEGER value with a {@code long} one. Note: if + * the LARGE_INTEGER value is {@code null} then it is consider greater + * than any {@code long} value. + * + * @param v1 The {@link LARGE_INTEGER} value + * @param v2 The {@code long} value + * @return 0 if values are equal, negative if 1st value less than 2nd one, + * positive otherwise. Note: the comparison uses the {@link #getValue()}. + * @see IntegerType#compare(long, long) + */ + public static int compare(LARGE_INTEGER v1, long v2) { + if (v1 == null) { + return 1; + } else { + return IntegerType.compare(v1.getValue(), v2); + } + } } /** @@ -1102,6 +1223,7 @@ public HANDLE(Pointer p) { } /** Override to the appropriate object for INVALID_HANDLE_VALUE. */ + @Override public Object fromNative(Object nativeValue, FromNativeContext context) { Object o = super.fromNative(nativeValue, context); if (WinBase.INVALID_HANDLE_VALUE.equals(o)) { @@ -1110,6 +1232,7 @@ public Object fromNative(Object nativeValue, FromNativeContext context) { return o; } + @Override public void setPointer(Pointer p) { if (immutable) { throw new UnsupportedOperationException("immutable reference"); @@ -1629,6 +1752,7 @@ public static class OSVERSIONINFO extends Structure { */ public char szCSDVersion[]; + @Override protected List getFieldOrder() { return Arrays.asList(new String[] { "dwOSVersionInfoSize", "dwMajorVersion", "dwMinorVersion", "dwBuildNumber", "dwPlatformId", "szCSDVersion" }); } @@ -1714,6 +1838,7 @@ public static class OSVERSIONINFOEX extends Structure { */ public byte wReserved; + @Override protected List getFieldOrder() { return Arrays.asList(new String[] { "dwOSVersionInfoSize", "dwMajorVersion", "dwMinorVersion", "dwBuildNumber", "dwPlatformId", "szCSDVersion", "wServicePackMajor", "wServicePackMinor", "wSuiteMask", "wProductType", "wReserved"}); } @@ -1919,6 +2044,7 @@ public static class EVENTLOGRECORD extends Structure { */ public DWORD DataOffset; + @Override protected List getFieldOrder() { return Arrays.asList(new String[] { "Length", "Reserved", "RecordNumber", "TimeGenerated", "TimeWritten", "EventID", "EventType", "NumStrings", "EventCategory", "ReservedFlags", "ClosingRecordNumber", "StringOffset", "UserSidLength", "UserSidOffset", "DataLength", "DataOffset"}); } @@ -2013,7 +2139,7 @@ public EVENTLOGRECORD(Pointer p) { * {@code Kernel32.QueryFullProcessImageName}). A handle that has the * {@link #PROCESS_QUERY_INFORMATION} access right is automatically granted * {@link #PROCESS_QUERY_LIMITED_INFORMATION}. - * + * * Windows Server 2003 and Windows XP: This access right is not supported. */ int PROCESS_QUERY_LIMITED_INFORMATION = 0x1000; @@ -2074,7 +2200,7 @@ public EVENTLOGRECORD(Pointer p) { int PROTECTED_SACL_SECURITY_INFORMATION = 0x40000000; int UNPROTECTED_DACL_SECURITY_INFORMATION = 0x20000000; int UNPROTECTED_SACL_SECURITY_INFORMATION = 0x10000000; - + /* Security control bits */ int SE_OWNER_DEFAULTED = 0x00000001; int SE_GROUP_DEFAULTED = 0x00000002; @@ -2090,8 +2216,8 @@ public EVENTLOGRECORD(Pointer p) { int SE_SACL_PROTECTED = 0x00002000; int SE_RM_CONTROL_VALID = 0x00004000; int SE_SELF_RELATIVE = 0x00008000; - - + + public static class SECURITY_DESCRIPTOR extends Structure { public static class ByReference extends SECURITY_DESCRIPTOR implements Structure.ByReference { @@ -2113,6 +2239,7 @@ public SECURITY_DESCRIPTOR(Pointer memory) { public byte[] data; + @Override protected List getFieldOrder() { return Arrays.asList(new String[] { "data" }); } @@ -2120,6 +2247,7 @@ protected List getFieldOrder() { public static class ACL extends Structure { + @Override protected List getFieldOrder() { return Arrays.asList(new String[] { "AclRevision", "Sbz1", "AclSize", "AceCount", "Sbz2" }); } @@ -2179,15 +2307,16 @@ public static class ByReference extends SECURITY_DESCRIPTOR_RELATIVE public int Sacl; public int Dacl; + @Override protected List getFieldOrder() { return Arrays.asList(new String[] { "Revision", "Sbz1", "Control", "Owner", "Group", "Sacl", "Dacl" }); } private ACL DACL; private PSID OWNER; - private PSID GROUP; + private PSID GROUP; private ACL SACL; - + public SECURITY_DESCRIPTOR_RELATIVE() { } @@ -2247,6 +2376,7 @@ public ACEStructure(Pointer p) { super(p); } + @Override protected List getFieldOrder() { return Arrays.asList(new String[] { "AceType", "AceFlags", "AceSize" }); } @@ -2273,6 +2403,7 @@ public ACE_HEADER(Pointer p) { * ACCESS_ALLOWED_ACE and ACCESS_DENIED_ACE have the same structure layout */ public static abstract class ACCESS_ACEStructure extends ACEStructure { + @Override protected List getFieldOrder() { List list = new ArrayList(super.getFieldOrder()); list.addAll(Arrays.asList(new String[] { "Mask", "SidStart"})); diff --git a/contrib/platform/test/com/sun/jna/platform/win32/Kernel32DiskManagementFunctionsTest.java b/contrib/platform/test/com/sun/jna/platform/win32/Kernel32DiskManagementFunctionsTest.java index b90931a226..ada3e4c3cf 100644 --- a/contrib/platform/test/com/sun/jna/platform/win32/Kernel32DiskManagementFunctionsTest.java +++ b/contrib/platform/test/com/sun/jna/platform/win32/Kernel32DiskManagementFunctionsTest.java @@ -64,11 +64,11 @@ private void testGetDiskFreeSpaceEx(String lpDirectoryName) { // System.out.append('\t').append("TotalNumberOfBytes: ").println(lpTotalNumberOfBytes); // System.out.append('\t').append("TotalNumberOfFreeBytes: ").println(lpTotalNumberOfFreeBytes); - assertTrue("No free size for " + lpDirectoryName, lpTotalNumberOfFreeBytes.getValue() > 0L); + assertTrue("No free size for " + lpDirectoryName, LARGE_INTEGER.compare(lpTotalNumberOfFreeBytes, 0L) > 0); assertTrue("Free size (" + lpTotalNumberOfFreeBytes + ")" + " not below total size (" + lpTotalNumberOfBytes + ")" + " for " + lpDirectoryName, - lpTotalNumberOfFreeBytes.getValue() < lpTotalNumberOfBytes.getValue()); + LARGE_INTEGER.compare(lpTotalNumberOfFreeBytes, lpTotalNumberOfBytes) < 0); } @Test diff --git a/contrib/platform/test/com/sun/jna/platform/win32/WinDefTypesTest.java b/contrib/platform/test/com/sun/jna/platform/win32/WinDefTypesTest.java new file mode 100644 index 0000000000..3eda148dfa --- /dev/null +++ b/contrib/platform/test/com/sun/jna/platform/win32/WinDefTypesTest.java @@ -0,0 +1,137 @@ +/* Copyright (c) 2007 Timothy Wall, All Rights Reserved + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + */ +package com.sun.jna.platform.win32; + +import java.lang.reflect.Constructor; +import org.junit.Test; + +import com.sun.jna.IntegerType; +import com.sun.jna.platform.win32.WinDef.BOOL; +import com.sun.jna.platform.win32.WinDef.CHAR; +import com.sun.jna.platform.win32.WinDef.DWORD; +import com.sun.jna.platform.win32.WinDef.DWORDLONG; +import com.sun.jna.platform.win32.WinDef.LONG; +import com.sun.jna.platform.win32.WinDef.LONGLONG; +import com.sun.jna.platform.win32.WinDef.SHORT; +import com.sun.jna.platform.win32.WinDef.UCHAR; +import com.sun.jna.platform.win32.WinDef.UINT; +import com.sun.jna.platform.win32.WinDef.ULONG; +import com.sun.jna.platform.win32.WinDef.ULONGLONG; +import com.sun.jna.platform.win32.WinDef.USHORT; +import com.sun.jna.platform.win32.WinDef.WORD; + +public class WinDefTypesTest extends AbstractWin32TestSupport { + + @Test + public void testComparableDWORD() throws Exception { + testComparableIntegerType(DWORD.class, 7365L, 3777347L); + } + + @Test + public void testComparableUINT() throws Exception { + testComparableIntegerType(UINT.class, 7365L, 3777347L); + } + + @Test + public void testComparableULONG() throws Exception { + testComparableIntegerType(ULONG.class, 7365L, 3777347L); + } + + @Test + public void testComparableULONGLONG() throws Exception { + testComparableIntegerType(ULONGLONG.class, 7365L, 3777347L); + } + + @Test + public void testComparableDWORDLONG() throws Exception { + testComparableIntegerType(DWORDLONG.class, 7365L, 3777347L); + } + + @Test + public void testComparableWORD() throws Exception { + testComparableIntegerType(WORD.class, 5637L, 7365L); + } + + @Test + public void testComparableUSHORT() throws Exception { + testComparableIntegerType(USHORT.class, 5637L, 7365L); + } + + @Test + public void testComparableSHORT() throws Exception { + testComparableIntegerType(SHORT.class, 5637L, 7365L); + } + + @Test + public void testComparableLONG() throws Exception { + testComparableIntegerType(LONG.class, 7365L, 3777347L); + } + + @Test + public void testComparableLONGLONG() throws Exception { + testComparableIntegerType(LONGLONG.class, 7365L, 3777347L); + } + + @Test + public void testComparableCHAR() throws Exception { + testComparableIntegerType(CHAR.class, 'a', 'z'); + } + + @Test + public void testComparableUCHAR() throws Exception { + testComparableIntegerType(UCHAR.class, 'a', 'z'); + } + + @Test + public void testComparableBOOL() { + assertEquals("Mismatched null/null comparison", 0, BOOL.compare(null, null)); + + BOOL FALSE = new BOOL(false); + BOOL TRUE = new BOOL(true); + + for (BOOL v : new BOOL[] { FALSE, TRUE }) { + assertEquals("Mismatched null/" + v + " object comparison", 1, BOOL.compare(null, v)); + assertEquals("Mismatched null/" + v + " value comparison", 1, BOOL.compare(null, v.booleanValue())); + assertEquals("Mismatched self/" + v + " comparison", 0, BOOL.compare(v, v.booleanValue())); + assertEquals("Mismatched self " + v + "#compareTo() result", 0, v.compareTo(v)); + assertEquals("Mismatched null " + v + "#compareTo() result", (-1), v.compareTo(null)); + } + + assertEquals("Mismatched natural order comparison", (-1), FALSE.compareTo(TRUE)); + assertEquals("Mismatched reversed order comparison", 1, TRUE.compareTo(FALSE)); + } + + public static > void testComparableIntegerType(Class clazz, long v1, long v2) throws Exception { + assertTrue(clazz.getSimpleName() + " test values not in natural order: v1=" + v1 + ", v2=" + v2, v1 < v2); + + Constructor ctor = clazz.getDeclaredConstructor(Long.TYPE); + testComparableIntegerType(clazz, ctor.newInstance(v1), ctor.newInstance(v2)); + } + + public static > void testComparableIntegerType(Class clazz, T v1, T v2) throws Exception { + assertTrue(clazz.getSimpleName() + " test values not in natural order: v1=" + v1 + ", v2=" + v2, v1.longValue() < v2.longValue()); + + assertEquals("Mismatched null/null comparison", 0, IntegerType.compare(null, null)); + assertEquals("Mismatched null/value comparison", 1, IntegerType.compare(null, v1)); + + assertEquals("Mismatched null/long comparison", 1, IntegerType.compare(null, v2.longValue())); + assertEquals("Mismatched natural order value/long comparison", -1, IntegerType.compare(v1, v2.longValue())); + assertEquals("Mismatched reversed order value/long comparison", 1, IntegerType.compare(v2, v1.longValue())); + assertEquals("Mismatched self value/long comparison", 0, IntegerType.compare(v1, v1.longValue())); + + assertEquals("Mismatched value/null comparison", (-1), v1.compareTo(null)); + assertEquals("Mismatched self value comparison", 0, v1.compareTo(v1)); + assertEquals("Mismatched natural order comparison", (-1), v1.compareTo(v2)); + assertEquals("Mismatched reversed order comparison", 1, v2.compareTo(v1)); + } +} diff --git a/contrib/platform/test/com/sun/jna/platform/win32/WinNTTypesTest.java b/contrib/platform/test/com/sun/jna/platform/win32/WinNTTypesTest.java new file mode 100644 index 0000000000..da8087f5b9 --- /dev/null +++ b/contrib/platform/test/com/sun/jna/platform/win32/WinNTTypesTest.java @@ -0,0 +1,47 @@ +/* Copyright (c) 2007 Timothy Wall, All Rights Reserved + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + */ +package com.sun.jna.platform.win32; + +import org.junit.Test; + +import com.sun.jna.platform.win32.WinNT.LARGE_INTEGER; + +public class WinNTTypesTest extends AbstractWin32TestSupport { + + @Test + public void testLargeIntegerLowHighLongValue() { + for (long expected : new long[] { + Long.MIN_VALUE, Integer.MIN_VALUE, Short.MIN_VALUE, Byte.MIN_VALUE, + 0L, + Long.MAX_VALUE, Integer.MAX_VALUE, Short.MAX_VALUE, Byte.MAX_VALUE + }) { + assertEquals("Mismatched value", expected, new LARGE_INTEGER.LowHigh(expected).longValue()); + } + } + + @Test + public void testLargeIntegerUnionLongValue() { + for (long expected : new long[] { + Long.MIN_VALUE, Integer.MIN_VALUE, Short.MIN_VALUE, Byte.MIN_VALUE, + 0L, + Long.MAX_VALUE, Integer.MAX_VALUE, Short.MAX_VALUE, Byte.MAX_VALUE + }) { + LARGE_INTEGER large = new LARGE_INTEGER(expected); + assertEquals("Mismatched large value", expected, large.getValue()); + + LARGE_INTEGER.LowHigh loHi = new LARGE_INTEGER.LowHigh(expected); + assertEquals("Mismatched low part", loHi.LowPart, large.getLow()); + assertEquals("Mismatched high part", loHi.HighPart, large.getHigh()); + } + } +} diff --git a/src/com/sun/jna/IntegerType.java b/src/com/sun/jna/IntegerType.java index 7785858dfa..8ddcac77b3 100644 --- a/src/com/sun/jna/IntegerType.java +++ b/src/com/sun/jna/IntegerType.java @@ -8,7 +8,7 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. + * Lesser General Public License for more details. */ package com.sun.jna; @@ -16,12 +16,12 @@ /** * Represents a native integer value, which may have a platform-specific size * (e.g. long on unix-based platforms). - * + * * May optionally indicate an unsigned attribute, such that when a value is * extracted into a larger-sized container (e.g. int retrieved * via {@link Number#longValue}, the value will be unsigned. Default behavior * is signed. - * + * * @author wmeissner@gmail.com * @author twalljava@java.net */ @@ -92,16 +92,18 @@ public void setValue(long value) { } } + @Override public Object toNative() { return number; } + @Override public Object fromNative(Object nativeValue, FromNativeContext context) { // be forgiving of null values read from memory long value = nativeValue == null ? 0 : ((Number) nativeValue).longValue(); try { - IntegerType number = (IntegerType) getClass().newInstance(); + IntegerType number = getClass().newInstance(); number.setValue(value); return number; } @@ -115,36 +117,99 @@ public Object fromNative(Object nativeValue, FromNativeContext context) { } } + @Override public Class nativeType() { return number.getClass(); } + @Override public int intValue() { return (int)value; } + @Override public long longValue() { return value; } + @Override public float floatValue() { return number.floatValue(); } + @Override public double doubleValue() { return number.doubleValue(); } + @Override public boolean equals(Object rhs) { return rhs instanceof IntegerType && number.equals(((IntegerType)rhs).number); } + @Override public String toString() { return number.toString(); } + @Override public int hashCode() { return number.hashCode(); } + + /** + * Compares 2 derived {@link IntegerType} values - Note: a + * {@code null} value is considered greater than any non-{@code null} + * one (i.e., {@code null} values are "pushed" to the end + * of a sorted array / list of values) + * + * @param v1 The 1st value + * @param v2 The 2nd value + * @return 0 if values are equal - including if both are {@code null}, + * negative if 1st value less than 2nd one, positive otherwise. Note: + * the comparison uses the {@link #longValue()}. + * @see #compare(long, long) + */ + public static int compare(T v1, T v2) { + if (v1 == v2) { + return 0; + } else if (v1 == null) { + return 1; // v2 cannot be null or v1 == v2 would hold + } else if (v2 == null) { + return (-1); + } else { + return compare(v1.longValue(), v2.longValue()); + } + } + + /** + * Compares a IntegerType value with a {@code long} one. Note: if + * the IntegerType value is {@code null} then it is consider greater + * than any {@code long} value. + * + * @param v1 The {@link IntegerType} value + * @param v2 The {@code long} value + * @return 0 if values are equal, negative if 1st value less than 2nd one, + * positive otherwise. Note: the comparison uses the {@link #longValue()}. + * @see #compare(long, long) + */ + public static int compare(IntegerType v1, long v2) { + if (v1 == null) { + return 1; + } else { + return compare(v1.longValue(), v2); + } + } + + // TODO if JDK 7 becomes the min. required use Long#compare(long,long) + public static final int compare(long v1, long v2) { + if (v1 == v2) { + return 0; + } else if (v1 < v2) { + return (-1); + } else { + return 1; + } + } } diff --git a/test/com/sun/jna/IntegerTypeTest.java b/test/com/sun/jna/IntegerTypeTest.java index ab8438f145..b0660c8926 100644 --- a/test/com/sun/jna/IntegerTypeTest.java +++ b/test/com/sun/jna/IntegerTypeTest.java @@ -15,6 +15,7 @@ public static class Sized extends IntegerType { public void testWriteNull() { class NTStruct extends Structure { public Sized field; + @Override protected List getFieldOrder() { return Arrays.asList(new String[] { "field" }); } @@ -25,6 +26,7 @@ protected List getFieldOrder() { public void testReadNull() { class NTStruct extends Structure { public Sized field; + @Override protected List getFieldOrder() { return Arrays.asList(new String[] { "field" }); } @@ -67,7 +69,7 @@ public void testCheckArgumentSize() { } } } - + public void testInitialValue() { long VALUE = 20; NativeLong nl = new NativeLong(VALUE); @@ -124,6 +126,14 @@ public UnsignedTestType(int size, long value) { assertTrue("Expected an unsigned value: " + tt.longValue(), tt.longValue() > 0); } + public void testCompareLongs() { + final long v1 = 7365L; + final long v2 = 3777347L; + assertEquals("Mismatched same value comparison", 0, IntegerType.compare(v1, v1)); + assertEquals("Mismatched natural order comparison", (-1), IntegerType.compare(v1, v2)); + assertEquals("Mismatched reversed order comparison", 1, IntegerType.compare(v2, v1)); + } + public static void main(String[] args) { junit.textui.TestRunner.run(IntegerTypeTest.class); }