Passing binary data from c extension back to ruby

I’m writing an extension in c that will take a string of space delimited
ascii like: “param1=value1 param2=value2 …”.

The c side function will produce some binary encoded data that will vary
in length based on the input string. The length will be known on the c
side after encoding. What is the best way to pass this buffer of raw
data back to ruby so it knows the length and doesn’t alter the data in
any way? All ruby will need to do with it is write it to a socket then
as raw bytes knowing the length…

I see there is rb_str_new2(char*) but the data is not null terminated on
the c side so I’m hesitant to use that conversion function.

thanks,

Kape

Kape K. [email protected] wrote:

I see there is rb_str_new2(char*) but the data is not null terminated on
the c side so I’m hesitant to use that conversion function.

rb_str_new(const char *ptr, long len);

Subject: passing binary data from c extension back to ruby
Date: ven 21 feb 14 11:58:00 +0100

Quoting Kape K. ([email protected]):

I see there is rb_str_new2(char*) but the data is not null terminated on
the c side so I’m hesitant to use that conversion function.

As you already could read, you can use rb_str_new, and pass to it the
pointer to your data and length in bytes. This function will generate
a String object, which includes length information (no need to rely on
null-termination, thus). From Ruby, pass it to Socket#write, and all
your bytes will be transmitted, without mangling.

You can also manipulate binary data in a String from ruby using
String#unpack and Array#pack. Say that your data contains three
short unsigned integers (16bit), two signed longs (32bit) and a double
(64bit) - thus, 22 bytes. You can do

array=string.unpack(‘SSSlld’)

and you will find in your array the six values. Array#pack does the
reverse:

string=[12,23,34,1010101,-332211,3.1415].pack(‘SSSlld’)
p string.bytes

gives

[12, 0, 23, 0, 34, 0, 181, 105, 15, 0, 77, 238, 250, 255, 111, 18, 131,
192, 202, 33, 9, 64]

Everything works smoothly as long as your string does not use a
multibyte
encoding. The default encoding for Ruby strings is UTF-8, but strings
generated by rb_str_new and Array#pack have ASCII-8BIT encoding.

Type

ri Array#pack

to know more.

Carlo