Class: VirtualBox::COM::FFI::Util

Inherits:
Object
  • Object
show all
Defined in:
lib/virtualbox/com/ffi/util.rb

Overview

Class which contains many class-level utility methods to assist with the FFI interface. These functions range from converting a function spec to a FFI parameter list to dereferencing pointers.

Class Method Summary collapse

Class Method Details

.camelize(string) ⇒ String

An “almost complete” camel-caser. Camel cases a string with a few exceptions. For example: ‘get_foo` becomes `GetFoo`, but `get_os_type` becomes `GetOSType` since `os` is a special case.

Parameters:

  • string (String)

    The string to camel case

Returns:

  • (String)


80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/virtualbox/com/ffi/util.rb', line 80

def camelize(string)
  special_cases = {
    "os" => "OS",
    "dhcp" => "DHCP",
    "dvd" => "DVD",
    "usb" => "USB",
    "vram" => "VRAM",
    "3d" => "3D",
    "bios" => "BIOS",
    "vrdp" => "VRDP",
    "vrde" => "VRDE",
    "hw" => "HW",
    "png" => "PNG",
    "io" => "IO",
    "apic" => "APIC",
    "acpi" => "ACPI",
    "pxe" => "PXE",
    "nat" => "NAT",
    "ide" => "IDE",
    "vfs" => "VFS",
    "ip" => "IP",
    "vdi" => "VDI",
    "cpu" => "CPU",
    "ram" => "RAM",
    "hdd" => "HDD",
    "rtc" => "RTC",
    "utc" => "UTC",
    "io" => "IO",
    "vm" => "VM"
  }

  parts = string.to_s.split(/_/).collect do |part|
    special_cases[part] || part.capitalize
  end

  parts.join("")
end

.interface_klass(type) ⇒ Class

Finds and returns the ‘COM::Interface` class associated with the type. If the class does not exist, a `NameError` will be raised.

Returns:

  • (Class)


13
14
15
# File 'lib/virtualbox/com/ffi/util.rb', line 13

def interface_klass(type)
  ::VirtualBox::COM::Util.versioned_interface(type)
end

.spec_to_ffi(spec) ⇒ Array

Converts a function spec from AbstractInterface 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`.

Parameters:

  • spec (Array)

    The function spec

Returns:

  • (Array)


31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/virtualbox/com/ffi/util.rb', line 31

def spec_to_ffi(spec)
  spec = spec.collect do |item|
    if item.is_a?(Array) && item[0] == :out
      if item[1].is_a?(Array)
        # The out is an array of items, so we add in two pointers:
        # one for size and one for the array
        [:pointer, :pointer]
      else
        # A regular out parameter is just a single pointer
        :pointer
      end
    elsif item.is_a?(Array) && item.length == 1
      # The parameter is an array of somethings
      [T_UINT32, :pointer]
    elsif item == WSTRING
      # Unicode strings are simply pointers
      :pointer
    elsif item.to_s[0,1] == item.to_s[0,1].upcase
      begin
        # Try to get the class from the interfaces
        interface = interface_klass(item.to_sym)

        if interface.superclass == COM::AbstractInterface
          :pointer
        elsif interface.superclass == COM::AbstractEnum
          T_UINT32
        end
      rescue NameError
        # Default to a pointer, since not all interfaces are implemented
        :pointer
      end
    else
      # Unknown items are simply passed as-is, hopefully FFI
      # will catch any problems
      item
    end
  end

  # Prepend a :pointer to represent the `this` parameter required
  # for the FFI parameter lists
  spec.unshift(:pointer).flatten
end

.versioned_interface(interface) ⇒ Class

Finds the versioned interface for the FFI module.

Returns:

  • (Class)


20
21
22
# File 'lib/virtualbox/com/ffi/util.rb', line 20

def versioned_interface(interface)
  ::VirtualBox::COM::FFI.const_get(::VirtualBox::COM::Util.version_const).const_get(interface)
end