I'm trying to pair with a connected iOS device and get the UDID using libimobiledevice and JNA. This is how I have declared the native functions:
static native int idevice_new(PointerByReference device, Pointer udid);
static native int lockdownd_client_new(Pointer device, PointerByReference client, String label);
static native int idevice_get_udid(Pointer idevice, StringByReference udid);
static native int lockdownd_query_type(Pointer lockdownd_client, StringByReference type);
For testing, I'm trying to do exactly what running the command idevicepair pair
does.
This is my main method:
PointerByReference device = new PointerByReference();
System.out.println("idevice_new error code: " + idevice_new(device, Pointer.NULL));
PointerByReference client = new PointerByReference();
System.out.println("lockdownd_client_new error code: " + lockdownd_client_new(device.getValue(), client, "java"));
StringByReference udid = new StringByReference();
System.out.println("idevice_get_udid error code: " + idevice_get_udid(device.getValue(), udid));
System.out.println("udid: " + udid.getValue());
StringByReference type = new StringByReference();
System.out.println("lockdownd_query_type error code: " + lockdownd_query_type(client.getValue(), type));
System.out.println("lockdownd_query_type: " + type.getValue());
System.out.println("lockdownd_pair error code: " + lockdownd_pair(client.getValue(), Pointer.NULL));
Whenever I try to get any string value, it outputs these weird question mark characters:
idevice_new error code: 0
lockdownd_client_new error code: 0
idevice_get_udid error code: 0
udid: ��AZ�
lockdownd_query_type error code: 0
lockdownd_query_type: �HbZ�
lockdownd_pair error code: 0
The characters are different each time.
In case you can't see it:
The UUID changes every time because it is unique! Each new one generated is different.
As for the strange characters, your mapping of the uuid
(and also type
) to StringByReference
is the culprit here, as you're not getting the data in the format it's stored in natively.
The method signature in C (which you should have posted with your question) notes that the type of uuid
is **char
, a Pointer to a pointer to a string of 8-bit C values. Digging into the source code, it appears they are the digits 0-9 and A-F in a string representation, and either 32 bytes (without hyphens) or 36 bytes (with) plus the null terminator. (Note this isn't always obvious; they could have been stored in 16 bytes as the full byte value, something the API should actually document.)
Internally, the StringByReference
class uses the Pointer.getString()
method:
public String getValue() {
return getPointer().getString(0);
}
The getString() method with only an offset uses your platform's default encoding, which is probably a multi-byte character set. This may not (and obviously doesn't, in your case) match the 8-bit encoding of the UUID.
You should map the UUID as a PointerByReference
and use uuid.getValue().getString(0, "UTF-8")
or uuid.getValue().getString(0, "US-ASCII")
to fetch the String as the 8-bit characters they represent.
(Alternately, you could get a byte array and create a String from it, although I'm not sure if you'll get the 32- or 36-byte result, so have fun if you go that route. For true fun, you can iterate the offset and read byte-by-byte until you get 0. But I digress.)
Doing the same thing for the type
field is left as an exercise for the reader.