Class: VirtualBox::COM::XPCOMC::Sig

Inherits:
Object
  • Object
show all
Defined in:
lib/virtualbox/com/xpcomc-ffi/sig.rb

Overview

Signatures are a list of type and direction (way: :in, :out) The type supported are simple types which resolved to Symbol or array of simple types

These types need to be “converted” to be interpreted corretly in the contexts of:

- callback
- writing arguments 
- reading arguments

Instance Method Summary collapse

Constructor Details

#initialize(sig) ⇒ Sig

Store and normalize signatures



16
17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/virtualbox/com/xpcomc-ffi/sig.rb', line 16

def initialize(sig)
    @sig = sig.map {|item|
        if item.is_a?(Array) && item[0] == :out 
        then [ item[1], :out ]
        else [ item,    :in  ]
        end
    }.freeze.each{|type, way|
        # Sanity check: only `[type]` or `type`
        if type.is_a?(Array) && type.length != 1
            raise ArgumentError,  "only arrays of simple type are supported"
        end
    }
end

Instance Method Details

#prepare_args(args = []) ⇒ Object

Prepare arguments by converting them to C structures



47
48
49
50
51
52
53
# File 'lib/virtualbox/com/xpcomc-ffi/sig.rb', line 47

def prepare_args(args=[])
    args = args.dup

    results = @sig.inject([]) do |results, item|
        single_type_to_arg(args, item, results)
    end
end

#read_values(args) ⇒ Object

Takes arguments list and returns the output from a function, properly dereferencing any output pointers.



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/virtualbox/com/xpcomc-ffi/sig.rb', line 58

def read_values(args)
    values, i = [], 0
    @sig.each do |type, way|
        # Array of type: [ type ] 
        # Skip 2: size + pointer to array
        if type.is_a?(Array)
            if way == :out
                size, type = args[i].read_uint32, type[0]
                values << if type == OCTET
                          then read_binary_blob(args[i+1], size)
                          else get_array_by_type(args[i+1], type, size)
                          end
            end
            i += 2  

        # Simple type  : type
        # Skip 1: pointer
        else
            if way == :out
                values << read_by_type(args[i], type)
            end
            i += 1
        end
    end
    
    case values.size when 0 then nil
                     when 1 then values.first
                     else        values
    end
end

#to_ffi_callbackObject

Converts a function signature to an FFI function spec. This handles custom types (unicode strings, arrays, and out-parameters) and will return a perfectly valid array ready to be passed into ‘callback`.



36
37
38
39
40
41
42
43
# File 'lib/virtualbox/com/xpcomc-ffi/sig.rb', line 36

def to_ffi_callback
    @sig.map {|type, way| is_array = type.is_a?(Array)
        case way
        when :out then is_array ? [:pointer, :pointer] : :pointer
        when :in  then is_array ? [:uint32,  :pointer] : mangling(type)[0]
        end
    }.unshift(:pointer).flatten	# Add `this` element
end