Ruby-FFI (ruby 1.8): чтение строк в кодировке UTF-16LE

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

Оборачиваю ли я функцию

attach_function [:getVersion, [], :pointer]

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

attach_function [:getVersion, [], :string]

Я получаю только первый символ, потому что второй символ равен нулю (\000), и в результате FFI перестает читать строку там, очевидно, потому что он предполагает, что имеет дело с нормальной строкой с одним нулем в конце.

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


person mydoghasworms    schedule 15.02.2012    source источник


Ответы (2)


Хорошо, это (неизящный) обходной путь, который у меня пока есть. Он включает добавление метода в 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
person mydoghasworms    schedule 15.02.2012

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

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
person graywolf    schedule 29.05.2018