Ruby-FFI(ruby 1.8):读取UTF-16LE编码的字符串

时间:2012-02-15 12:23:33

标签: ruby ffi ruby-1.8

我正在使用Ruby 1.8上的Ruby-FFI来包装一个使用UTF-16LE字符串的库。该库有一个返回这样一个String的C函数。

我是否用

包装函数
attach_function [:getVersion, [], :pointer]

并在返回的指针上调用read_string,或者是否用

包装它
attach_function [:getVersion, [], :string]

我得到的只是第一个字符,因为第二个字符为空(\000),因此,FFI停止在那里读取字符串,显然是因为它假设它正在处理正常的单个字符-null终止字符串。

我需要做些什么,可能是在初始化我的Ruby程序或FFI或其他方面,让它知道我希望字符串是UTF-16LE编码的吗?我怎么能绕过这个?

2 个答案:

答案 0 :(得分:1)

好的,这是我到目前为止(不优雅)的解决方法。它涉及到FFI :: Pointer添加一个方法。在我的库的上下文中调用应该是安全的,因为所有字符串都应该是UTF-16LE编码的,否则,它可能不是很好,因为它可能永远不会遇到double null并且只会继续读取内存中字符串的边界。

module FFI
  class Pointer

    # Read string until we encounter a double-null terminator
    def read_string_dn
      cont_nullcount = 0
      offset = 0
      # Determine the offset in memory of the expected double-null
      until cont_nullcount == 2
        byte = get_bytes(offset,1)
        cont_nullcount += 1 if byte == "\000"
        cont_nullcount = 0 if byte != "\000"
        offset += 1
      end
      # Return string with calculated length (offset) including terminator
      get_bytes(0,offset+1)
    end

  end

end

答案 1 :(得分:0)

基于相同想法的更优雅的解决方案。也处理编码。

module FFI
  class Pointer
    def read_wstring
      offset = 0
      while get_bytes(offset, 2) != "\x00\x00"
        offset += 2
      end
      get_bytes(0, offset).force_encoding('utf-16le').encode('utf-8')
    end
  end
end