1

I am porting the openvr sample to jogl, after we created the binding with jna.

Almost at the end (before rendering the controllers and the tracking base stations), I got stuck trying to translate a char pointer in C to a String in Java.

C++ code here:

//-----------------------------------------------------------------------------
// Purpose: Helper to get a string from a tracked device property and turn it
//          into a std::string
//-----------------------------------------------------------------------------
std::string GetTrackedDeviceString( vr::IVRSystem *pHmd, vr::TrackedDeviceIndex_t unDevice, vr::TrackedDeviceProperty prop, vr::TrackedPropertyError *peError = NULL )
{
    uint32_t unRequiredBufferLen = pHmd->GetStringTrackedDeviceProperty( unDevice, prop, NULL, 0, peError );
    if( unRequiredBufferLen == 0 )
        return "";

    char *pchBuffer = new char[ unRequiredBufferLen ];
    unRequiredBufferLen = pHmd->GetStringTrackedDeviceProperty( unDevice, prop, pchBuffer, unRequiredBufferLen, peError );
    std::string sResult = pchBuffer;
    delete [] pchBuffer;
    return sResult;
}

GetStringTrackedDeviceProperty here:

/** Returns a string property. If the device index is not valid or the property is not a string type this function will 
* return 0. Otherwise it returns the length of the number of bytes necessary to hold this string including the trailing
* null. Strings will generally fit in buffers of k_unTrackingStringSize characters. */
virtual uint32_t GetStringTrackedDeviceProperty( vr::TrackedDeviceIndex_t unDeviceIndex, ETrackedDeviceProperty prop, VR_OUT_STRING() char *pchValue, uint32_t unBufferSize, ETrackedPropertyError *pError = 0L ) = 0;

Where VR_OUT_STRING() is defined here as:

# define VR_CLANG_ATTR(ATTR)

#define VR_OUT_STRING() VR_CLANG_ATTR( "out_string: ;" )

I have already done something similar where I had to call a function that expect the pointer to an array of TrackedDevicePose_t structures:

private TrackedDevicePose_t.ByReference trackedDevicePosesReference = new TrackedDevicePose_t.ByReference();
public TrackedDevicePose_t[] trackedDevicePose
            = (TrackedDevicePose_t[]) trackedDevicePosesReference.toArray(VR.k_unMaxTrackedDeviceCount);

I created first the reference and then from it the actual array.

But here I can't have a class extending the char array..

private String getTrackedDeviceString(IVRSystem hmd, int device, int prop, IntBuffer propError) {

    int requiredBufferLen = hmd.GetStringTrackedDeviceProperty.apply(device, prop, Pointer.NULL, 0, propError);

    if(requiredBufferLen == 0) {
        return "";
    }


    CharArray.ByReference charArrayReference = new CharArray.ByReference();
    char[] cs = charArrayReference.toArray(requiredBufferLen);

    return null;
}

Where apply (here) is:

public interface GetStringTrackedDeviceProperty_callback extends Callback {

    int apply(int unDeviceIndex, int prop, Pointer pchValue, int unBufferSize, IntBuffer pError);
};

CharArray class, crap attempt here

Any ideas?

6
  • 1
    Your code is C++, not C. These are different languages, and the differences matter. Commented Aug 30, 2016 at 13:04
  • Moreover, I don't see where Java comes into it. If you mean to interface directly with Java then that requires JNI, and I see no JNI anywhere. If you have a looser interaction in mind, such as via an intermediary file or pipe, then those details are important. Commented Aug 30, 2016 at 13:07
  • Yep, you are right John, thanks, I just fixed it. Java comes into with the binding, I also added that right now. Commented Aug 30, 2016 at 13:11
  • As an aside -- pHmd->GetStringTrackedDeviceProperty -- If the implementation of this function throws, your GetTrackedDeviceString has a memory leak due to the new char[ unRequiredBufferLen ]; Commented Aug 30, 2016 at 13:17
  • JNA automatically handles conversion from NUL-terminated C strings into Java String. It also provides Native.toString() to manually perform conversions. Commented Aug 31, 2016 at 10:47

1 Answer 1

1

I've done some porting of C and C++ code to Java, and while it's probably horribly hacky, the best I've come up with to solve cases where a pointer to an int primitive or a char*/String is needed for a function call, is to create a small wrapper class with a single property, pass that object into the function, change the property as needed, and retrieve the new value after the function call. So something like:

public class StringPointer {
    public String value = "";
}

StringPointer pchBuffer = new StringPointer();
unRequiredBufferLen = pHmd.GetStringTrackedDeviceProperty( unDevice, prop, pchBuffer, unRequiredBufferLen, peError );
String sResult = pchBuffer.value;

and inside GetStringTrackedDeviceProperty()

...
pchValue.value = "some string";
...

In this case, you can use a String, since that's what your code is doing with the char* after the function call, but if it actually really needs to be a char[], you can just create char[] pchBuffer = new char[unRequiredBufferLen]; and pass that into the function. It will be just like you were using a char* in C++, and any changes you make inside the array will be visible after the function ends, and you can even do String sResult = new String(pchBuffer);.

Sign up to request clarification or add additional context in comments.

6 Comments

Interesting idea, I'll give it a try
So, about the first method, I can't to that because GetStringTrackedDeviceProperty is of type interface GetStringTrackedDeviceProperty_callback that extends Callback and therefore it cannot have any body. However I also tried your second tip, by changing the argument from jna Pointer to char[], it works but I get a weird result, 桬扟獡獥慴楴湯癟癩e, on C++ I get lighthouse...
The C++ part is probably using single-byte characters. If you break each char down into its individual bytes, does that get you the correct answer?
Switching from char to byte buffer worked, thanks dear!
Ps: let me just add this, using jna Native.toString(buffer) instead of new String(buffer) removes automatically any ending space
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.