Skip to content

Commit 68abf0e

Browse files
committed
Better way to handle no null
1 parent 1e9cb70 commit 68abf0e

File tree

2 files changed

+40
-23
lines changed

2 files changed

+40
-23
lines changed

contrib/platform/src/com/sun/jna/platform/win32/Cfgmgr32Util.java

+35-22
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
*/
2424
package com.sun.jna.platform.win32;
2525

26+
import java.io.UnsupportedEncodingException;
27+
2628
import com.sun.jna.Memory;
2729
import com.sun.jna.Native;
2830
import com.sun.jna.ptr.IntByReference;
@@ -33,6 +35,18 @@
3335
* @author widdis[at]gmail[dot]com
3436
*/
3537
public abstract class Cfgmgr32Util {
38+
@SuppressWarnings("serial")
39+
public static class Cfgmgr32Exception extends RuntimeException {
40+
private final int errorCode;
41+
42+
public Cfgmgr32Exception(int errorCode) {
43+
this.errorCode = errorCode;
44+
}
45+
46+
public int getErrorCode() {
47+
return errorCode;
48+
}
49+
}
3650

3751
/**
3852
* Utility method to call Cfgmgr32's CM_Get_Device_ID that allocates the
@@ -43,41 +57,40 @@ public abstract class Cfgmgr32Util {
4357
* Caller-supplied device instance handle that is bound to the
4458
* local machine.
4559
* @return The device instance ID string.
60+
* @throws UnsupportedEncodingException
4661
*/
47-
public static String CM_Get_Device_ID(int devInst) {
62+
public static String CM_Get_Device_ID(int devInst) throws UnsupportedEncodingException {
4863
int charToBytes = Boolean.getBoolean("w32.ascii") ? 1 : Native.WCHAR_SIZE;
4964

5065
// Get Device ID character count
5166
IntByReference pulLen = new IntByReference();
5267
Cfgmgr32.INSTANCE.CM_Get_Device_ID_Size(pulLen, devInst, 0);
5368

54-
// Add 1 for null terminator
55-
int deviceIdLength = pulLen.getValue() + 1;
56-
Memory buffer = new Memory(deviceIdLength * charToBytes);
57-
// Fetch the buffer
58-
int ret = Cfgmgr32.INSTANCE.CM_Get_Device_ID(devInst, buffer, deviceIdLength, 0);
69+
// Zero and Fetch the buffer
70+
Memory buffer = new Memory(pulLen.getValue() * charToBytes);
71+
buffer.clear();
72+
int ret = Cfgmgr32.INSTANCE.CM_Get_Device_ID(devInst, buffer, pulLen.getValue(), 0);
5973
// In the unlikely event the device id changes this might not be big
60-
// enough, try again
61-
while (ret == Cfgmgr32.CR_BUFFER_SMALL) {
74+
// enough, try again. This happens rarely enough one retry should be
75+
// sufficient.
76+
if (ret == Cfgmgr32.CR_BUFFER_SMALL) {
6277
Cfgmgr32.INSTANCE.CM_Get_Device_ID_Size(pulLen, devInst, 0);
63-
deviceIdLength = pulLen.getValue() + 1;
64-
buffer = new Memory(deviceIdLength * charToBytes);
65-
ret = Cfgmgr32.INSTANCE.CM_Get_Device_ID(devInst, buffer, deviceIdLength, 0);
78+
buffer = new Memory(pulLen.getValue() * charToBytes);
79+
buffer.clear();
80+
ret = Cfgmgr32.INSTANCE.CM_Get_Device_ID(devInst, buffer, pulLen.getValue(), 0);
6681
}
67-
68-
// Convert buffer to Java String
82+
// If we still aren't successful throw an exception
83+
if (ret != Cfgmgr32.CR_SUCCESS) {
84+
throw new Cfgmgr32Exception(ret);
85+
}
86+
// Convert buffer to Java String (may include a null). Since we've
87+
// cleared it we can rely on trim()
6988
String deviceId;
7089
if (charToBytes == 1) {
71-
deviceId = buffer.getString(0);
90+
deviceId = new String(buffer.getByteArray(0, pulLen.getValue()), "US-ASCII");
7291
} else {
73-
deviceId = buffer.getWideString(0);
74-
}
75-
// Edge case where there's not enough room for null terminator
76-
// but returns successfully. In this case getString() grabs stray
77-
// characters from memory outside our buffer.
78-
if (deviceId.length() > deviceIdLength) {
79-
deviceId = deviceId.substring(0, deviceIdLength);
92+
deviceId = new String(buffer.getCharArray(0, pulLen.getValue()));
8093
}
81-
return deviceId;
94+
return deviceId.trim();
8295
}
8396
}

contrib/platform/test/com/sun/jna/platform/win32/Cfgmgr32Test.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
import static org.junit.Assert.assertEquals;
2727
import static org.junit.Assert.assertTrue;
2828

29+
import java.io.UnsupportedEncodingException;
30+
2931
import org.junit.Test;
3032

3133
import com.sun.jna.ptr.IntByReference;
@@ -60,9 +62,11 @@ public void testDevNode() {
6062

6163
/**
6264
* Tests CM_Locate_DevNode, CM_Get_Device_ID_Size, CM_Get_Device_ID
65+
*
66+
* @throws UnsupportedEncodingException
6367
*/
6468
@Test
65-
public void testDeviceID() {
69+
public void testDeviceID() throws UnsupportedEncodingException {
6670
// Fetch the root node
6771
IntByReference outputNode = new IntByReference();
6872
assertEquals(Cfgmgr32.CR_SUCCESS,

0 commit comments

Comments
 (0)