Question

I need to interface Ruby with a C-function which does low-level byte operations on a fixed-sized buffer (16 bytes length).

I should also mention that I am using Ruby 1.8.7 for this, so no headaches with Ruby trying to figure out encodings.

 void transmogrify(unsigned char *data_in, unsigned_char *data_out)
 {
   unsigned char buffer[16];
   for(i=0;i<16;i++) {
     buffer[i] = data_in[i] << 2;  // some low level operations on 8-bit values here
   }
   memcpy(data_out, buffer, sizeof(buffer));
 }        

How do I write the Ruby C-interface code in my library, so that it will handle binary data in strings correctly? e.g. that it will be robust against zero bytes in the fixed-length input string?

If I use StringValuePtr() it breaks on zero bytes.

 static VALUE mygem_transmogrify(VALUE self, VALUE input)
 {
   unsigned char output[16]
   if (TYPE(input) != T_STRING) { return Qnil; }  // make sure input is a String
   StringValuePtr(input);  // <--- THIS does not like zero bytes in the string
   transmogrify( (unsigned char *) RSTRING_PTR(input) , (unsigned char *) output);
   return rb_str_new( (char *) output, 16);
 }

I want to call this from Ruby as follows:

input_string = File.read( 'somefile')       # reads 16 bytes binary
output = MyGem.transmogrify( input_string ) # output should be 16 bytes binary

 => ... in 'transmogrify': string contains null butye (ArgumentError)
Was it helpful?

Solution

I figured it out:

 static VALUE mygem_transmogrify(VALUE self, VALUE input)
 {
   unsigned char output[16]
   if (TYPE(input) != T_STRING) { return Qnil; }  // make sure input is a String
   transmogrify( (unsigned char *) RSTRING(input)->ptr , (unsigned char *) output);
   return rb_str_new( (char *) output, 16);
 }

this does not break on zero bytes in the input string.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top