Ruby-FFI (ruby 1.8): чтение строк в кодировке UTF-16LE - PullRequest
0 голосов
/ 15 февраля 2012

Я работаю с Ruby-FFI на Ruby 1.8, чтобы обернуть библиотеку, которая использует строки UTF-16LE. В библиотеке есть функция C, которая возвращает такую ​​строку.

Обертываю ли я функцию с

attach_function [:getVersion, [], :pointer]

и вызову read_string возвращаемого указателя, или я обертываю его

attach_function [:getVersion, [], :string]

То, что я получаю, это только первый символ, потому что второй символ равен нулю (\000), и в результате FFI прекращает чтение строки там, очевидно, потому что предполагает, что имеет дело с обычным, единичным нулем завершенная строка.

Есть ли что-то, что мне нужно сделать, возможно, при инициализации моей программы Ruby или FFI или иным образом, чтобы я знал, что строки ожидают в кодировке UTF-16LE? Как еще можно обойти это?

Ответы [ 2 ]

1 голос
/ 15 февраля 2012

ОК, это (не изящный) обходной путь, который у меня есть до сих пор. Это включает добавление метода в FFI :: Pointer. Это должно быть безопасно для вызова в контексте моей библиотеки, потому что все строки должны быть в кодировке UTF-16LE, но в противном случае это может быть не очень хорошо, потому что он может никогда не встретить двойной ноль и просто продолжит чтение после границы строки в памяти.

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
0 голосов
/ 29 мая 2018

Более элегантное решение, основанное на той же идее. Работает ли с кодировкой тоже.

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
...