How to convert cdata structure to lua string?

I am in the middle of writing a small application that needs to read some complex binary messages in LuaJit.

I used a bit module and string.rep. However, all this is very cumbersome. I'm new to using LuaJit and I think it might be a lot easier to use FFI.

In C, I can declare a structure as follows:

struct mystruct { uint32_t field1; char field2[6]; uin64_t field3; short field4; } __attribute__(packed); 

When reading LuaJit FFI it seems like you can declare

 ffi.cdef[[ #pragma pack(1) struct mystruct { uint32_t field1; char field2[6]; uin64_t field3; short field4; }; ]] 

Then I can create tinsel and access these fields:

 local ms = ffi.new("mystruct") ms.field1 = 32; // ... etc 

But how do I convert this back to a lua string?

I tried this, but it seems he did not do what he wanted.

 local s = tostring(ms) 

and this:

 local s = ffi.string(ms) 

throws the following error: "bad argument # 1 to" string (cannot convert "struct mystruct" to "const char *") "

So I tried a throw:

 local s = ffi.string(ffi.cast("char*", ms)) 

There is no error, but on the explorer it does not look right.

+4
source share
1 answer

You must explicitly specify the length when using ffi.string with a parameter other than a string:

str = ffi.string (ptr [, len])

Creates an internal Lua string from the data ptr points to.

If the optional len argument is missing, ptr is converted to "char *", and it is assumed that the data has zero completion. The length of the string is calculated using strlen ().

When I run the following code, I get the expected result (small end):

 ffi = require 'ffi' ffi.cdef[[ typedef unsigned long uint32_t; typedef unsigned long long uint64_t; #pragma pack(1) struct mystruct { uint32_t field1; char field2[6]; uint64_t field3; short field4; }; ]] function string.tohex(str) return (str:gsub('.', function (c) return string.format('%02X', string.byte(c)) end)) end ms = ffi.new('struct mystruct', 1, {2, 3, 4, 5, 6, 7}, 8, 9) s = ffi.string(ms, ffi.sizeof(ms)) -- specify how long the byte sequence is print(s:tohex()) --> 0100000002030405060708000000000000000900 

Update: I know this is not part of the original question, but I just found out this trick, and in order to be complete, here is a way to convert Lua string back to FFI cdata

  data = ffi.new('struct mystruct') -- create a new cdata ffi.copy(data, s, ffi.sizeof(data)) -- fill it with data from Lua string 's' print(data.field1, data.field4) --> 1 9 
+12
source

Source: https://habr.com/ru/post/1433267/


All Articles