I think you can do something like this:
Header
#include <hx/CFFI.h>
Creating a buffer
value bytes;
int length = 100;
unsigned char* data;
buffer b = alloc_buffer_len (length);
data = (unsigned char*)buffer_data (b);
if (data) {
bytes = buffer_val (b);
} else {
bytes = alloc_raw_string (length);
data = (unsigned char*)val_string (s);
}
Filling the buffer with data
for (int i = 0; i < length; i++) {
data[i] = i;
}
Returning it to Haxe
value object = alloc_empty_object ();
alloc_field (object, val_id ("b"), bytes);
alloc_field (object, val_id ("length"), alloc_int (length));
return object;
On the Haxe C++ target, I think you can return the bytes
value directly back to Haxe, and treat it as a haxe.io.Bytes
instance. Something like that. In Lime, we support both HXCPP and Neko (and will support more virtual machines in the future), so it is not possible to pass it back directly. This is also where the alloc_raw_string
comes in, as some targets (IE, Neko) don’t support the buffer type. We use something like the above, where we allocate an empty Haxe object and set it’s fields. We then use this to create a haxe.io.Bytes
instance on the Haxe side:
var data = make_cffi_call (); // the CFFI method that is returning the object
var bytes = @:privateAccess new Bytes (data.length, data.b);
The Lime array buffer types, as well as the OpenFL ByteArray
type, support conversion from Haxe Bytes
. They are abstracts, so it’s a lightweight conversion just to change how you read the data – it does not perform a copy. Once you have your Bytes
, you can treat it how you feel most comfortable
var byteArray:ByteArray = cast bytes;
In Lime, we cache the val_id
calls to save a bit of performance, but I believe the above code is pretty much the gist of what we use