Rubi Noobie: Como definir um valor de string em uma FFI Struct
Pergunta
Eu estou tendo alguns problemas iniciantes Definição de um struct FFI em Ruby. O que eu quero fazer é passar um ponteiro para uma string C, definindo uma propriedade string em uma FFI :: Struct objeto:
class SpSessionConfig < FFI::Struct
layout :api_version, :int,
:cache_location, :string,
:settings_location, :string,
:application_key, :pointer,
:application_key_size, :int,
:user_agent, :string,
:sp_session_callbacks, :pointer,
:user_data, :pointer
end
end
sessionConf = SpotifyLibrary::SpSessionConfig.new()
puts sessionConf # => '#<SpotifyLibrary::SpSessionConfig:0x9acc00c>'
sessionConf[:api_version] = 1
puts "Api Version: #{sessionConf[:api_version]}"
myTempDir = "tmp"
sessionConf[:cache_location] = myTempDir # !Error!
Mas quando eu executar o código eu recebo este erro:
jukebox.rb:44:in `[]=': Cannot set :string fields (ArgumentError)
from jukebox.rb:44:in `<main>'
Então, eu realmente não sei para onde ir a partir daqui.
Além disso, se você souber de qualquer bom documtation ou tutoriais sobre este assunto, por favor deixar uma resposta! Até agora eu encontrei a documentação wiki em projeto Kenai muito útil, mas quanto mais, melhor!
Obrigado!
Eu tentei declarar os membros de dados String como [: char, 5], mas que lhe dá outro erro:
jukebox.rb:44:in `put': put not supported for FFI::StructLayoutBuilder::ArrayField_Signed8_3 (ArgumentError)
from jukebox.rb:44:in `[]='
from jukebox.rb:44:in `<main>
Não é uma boa sugestão para experimentar o tipo de ponteiro de memória e vou tentar que depois do trabalho hoje.
Solução
FFI rejeita automaticamente seqüências de configuração. Tente mudá-lo a partir de: corda para: char_array, como mencionado na desta página :
: char_array - utilizado apenas em um layout struct onde struct tem uma série de estilo C (char []) como membro
Se isso não funcionar, você vai ter que usar um: ponteiro e convertê-lo de volta em uma string. Não é bem documentado, mas MemoryPointer tem um monte de funções disponíveis , como write_string
, que deve ajudar.
Outras dicas
Assim, graças à resposta de Pesto (aceite) Eu encontrei uma solução. write_string retornos cedo se existe um zero bytes no tampão (segue semântica string C). Aqui está o código para quem pode tropeçar este problema no futuro.
# Open my application key file and store it in a byte array
appkeyfile = File.read("spotify_appkey.key")
# get the number of bytes in the key
bytecount = appkeyfile.unpack("C*").size
# create a pointer to memory and write the file to it
appkeypointer = FFI::MemoryPointer.new(:char, bytecount)
appkeypointer.put_bytes(0, appkeyfile, 0, bytecount)