virtualbox-com 0.9.9 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +339 -19
- data/examples/simple.rb +2 -0
- data/ext/virtualbox-com/4.1/extconf.rb +4 -0
- data/ext/virtualbox-com/4.1/generated.inc +17345 -0
- data/ext/virtualbox-com/4.1/vbox.c +858 -0
- data/ext/virtualbox-com/4.2/extconf.rb +4 -0
- data/ext/virtualbox-com/4.2/generated.inc +19751 -0
- data/ext/virtualbox-com/4.2/vbox.c +858 -0
- data/ext/virtualbox-com/helpers.h +62 -0
- data/ext/virtualbox-com/loader/extconf.rb +3 -0
- data/ext/virtualbox-com/loader/vbox-loader.c +187 -0
- data/ext/virtualbox-com/types.h +34 -0
- data/ext/virtualbox-com/vbox.c +858 -0
- data/lib/virtualbox/com.rb +4 -26
- data/lib/virtualbox/com/{abstract_enum.rb → abstracts.rb} +22 -18
- data/lib/virtualbox/com/exceptions.rb +29 -3
- data/lib/virtualbox/com/model/4.1-generated.rb +2141 -0
- data/lib/virtualbox/com/model/4.2-generated.rb +141 -432
- data/lib/virtualbox/com/model/4.2.rb +4 -4
- data/lib/virtualbox/com/util.rb +2 -1
- data/lib/virtualbox/com/version.rb +1 -1
- data/lib/virtualbox/com/xpcomc-ffi.rb +5 -19
- data/lib/virtualbox/com/xpcomc-ffi/abstracts.rb +103 -0
- data/lib/virtualbox/com/{iid.rb → xpcomc-ffi/iid.rb} +18 -0
- data/lib/virtualbox/com/xpcomc-ffi/lib.rb +6 -0
- data/lib/virtualbox/com/xpcomc-ffi/model-types.rb +1 -0
- data/lib/virtualbox/com/xpcomc-native.rb +8 -0
- data/scripts/abstracts.rb +84 -0
- data/scripts/sig.rb +201 -0
- data/scripts/spec.rb +56 -0
- data/scripts/to_c.rb +157 -0
- data/scripts/xidl-conv.rb +110 -50
- data/virtualbox-com.gemspec +18 -11
- metadata +49 -47
- data/.gitignore +0 -9
- data/README.md +0 -89
- data/Rakefile +0 -8
- data/lib/virtualbox/com/abstract_interface.rb +0 -144
- data/lib/virtualbox/com/abstract_model.rb +0 -14
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
|
2
2
|
require 'set'
|
3
3
|
|
4
4
|
module VirtualBox
|
@@ -6,7 +6,7 @@ module COM
|
|
6
6
|
module Model
|
7
7
|
|
8
8
|
|
9
|
-
class Machine <
|
9
|
+
class Machine < NSISupports
|
10
10
|
ONLINE_STATES = Set.new [ :running,
|
11
11
|
:paused,
|
12
12
|
:stuck,
|
@@ -30,7 +30,7 @@ end
|
|
30
30
|
|
31
31
|
|
32
32
|
|
33
|
-
class Progress <
|
33
|
+
class Progress < NSISupports
|
34
34
|
# This method blocks the execution while the operations represented
|
35
35
|
# by this {Progress} object execute, but yields a block every `x`
|
36
36
|
# percent (interval given in parameters).
|
@@ -62,7 +62,7 @@ class Progress < AbstractInterface
|
|
62
62
|
end
|
63
63
|
|
64
64
|
|
65
|
-
class EventSource <
|
65
|
+
class EventSource < NSISupports
|
66
66
|
MODEL_MAP = {
|
67
67
|
:machine_event => :MachineEvent,
|
68
68
|
:snapshot_event => :SnapshotEvent,
|
data/lib/virtualbox/com/util.rb
CHANGED
@@ -60,6 +60,7 @@ module Util
|
|
60
60
|
"bios" => "BIOS",
|
61
61
|
"csam" => "CSAM",
|
62
62
|
"dhcp" => "DHCP",
|
63
|
+
"ehci" => "EHCI",
|
63
64
|
"fifo" => "FIFO",
|
64
65
|
"hpet" => "HPET",
|
65
66
|
"ich6" => "ICH6",
|
@@ -75,6 +76,7 @@ module Util
|
|
75
76
|
"tftp" => "TFTP",
|
76
77
|
"uuid" => "UUID",
|
77
78
|
"vbox" => "VBox",
|
79
|
+
"vhwa" => "VHWA",
|
78
80
|
"vpid" => "VPID",
|
79
81
|
"vram" => "VRAM",
|
80
82
|
"vrde" => "VRDE",
|
@@ -127,7 +129,6 @@ module Util
|
|
127
129
|
"vm" => "VM",
|
128
130
|
"vd" => "VD",
|
129
131
|
}
|
130
|
-
|
131
132
|
end
|
132
133
|
|
133
134
|
end
|
@@ -10,31 +10,17 @@ require_relative 'xpcomc-ffi/model-types'
|
|
10
10
|
|
11
11
|
module VirtualBox
|
12
12
|
module COM
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
:m1, :uint16,
|
17
|
-
:m2, :uint16,
|
18
|
-
:m3, [:uint8, 8]
|
19
|
-
end
|
20
|
-
|
21
|
-
def to_ffi
|
22
|
-
@ffi ||= begin
|
23
|
-
data = FFIStruct.new
|
24
|
-
data[:m0] = to_a[0]
|
25
|
-
data[:m1] = to_a[1]
|
26
|
-
data[:m2] = to_a[2]
|
27
|
-
to_a[3..-1].each_index{|i| data[:m3][i] = to_a[3..-1][i] }
|
28
|
-
data.freeze
|
29
|
-
end
|
13
|
+
module Model
|
14
|
+
def self.create(name, *args)
|
15
|
+
self.get(name).new(*args)
|
30
16
|
end
|
31
17
|
end
|
32
18
|
end
|
33
19
|
end
|
34
20
|
|
35
|
-
|
36
|
-
|
37
21
|
# Load FFI implementation
|
22
|
+
require_relative 'xpcomc-ffi/iid'
|
23
|
+
require_relative 'xpcomc-ffi/abstracts'
|
38
24
|
require_relative 'xpcomc-ffi/xpcomc-vbox'
|
39
25
|
require_relative 'xpcomc-ffi/binding'
|
40
26
|
require_relative 'xpcomc-ffi/implementer'
|
@@ -0,0 +1,103 @@
|
|
1
|
+
module VirtualBox
|
2
|
+
module COM
|
3
|
+
|
4
|
+
class AbstractModel
|
5
|
+
def self.iid(str)
|
6
|
+
const_set(:IID, IID.new(str))
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
#
|
12
|
+
# # Defining an Interface
|
13
|
+
#
|
14
|
+
# Defining an interface is done by subclassing AbstractInterface and
|
15
|
+
# using the provided class methods to define the COM methods and
|
16
|
+
# properties. A small example class is shown below:
|
17
|
+
#
|
18
|
+
# class Time < AbstractInterface
|
19
|
+
# function :now, [[:out, :uint]]
|
20
|
+
# property :hour, :uint
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# # Accessing an Interface
|
24
|
+
#
|
25
|
+
#
|
26
|
+
# # Assume `time` was retrieved already
|
27
|
+
# puts time.foo.to_s
|
28
|
+
# time.hour = 20
|
29
|
+
# x = time.now
|
30
|
+
#
|
31
|
+
# The above example shows how the properties and functions can be used
|
32
|
+
# with a given interface.
|
33
|
+
#
|
34
|
+
class AbstractInterface < AbstractModel
|
35
|
+
attr_reader :implementer
|
36
|
+
|
37
|
+
class << self
|
38
|
+
# Adds a function to the interface
|
39
|
+
def function(name, type, args, opts={})
|
40
|
+
h[name] = Spec::Function.new(name, type, args, opts)
|
41
|
+
define_method(name) { |*args|
|
42
|
+
@implementer.call_function(spec, *args)
|
43
|
+
} unless spec.hide?
|
44
|
+
end
|
45
|
+
|
46
|
+
# Adds a property to the interface
|
47
|
+
def property(name, type, opts={})
|
48
|
+
h[name] = Spec::Property.new(name, type, opts)
|
49
|
+
define_method(name) {
|
50
|
+
@implementer.read_property(spec)
|
51
|
+
} unless spec.hide?
|
52
|
+
define_method(:"#{name}=") { |value|
|
53
|
+
@implementer.write_property(spec, value)
|
54
|
+
} unless spec.hide? || spec.readonly?
|
55
|
+
end
|
56
|
+
|
57
|
+
# Get a member by name
|
58
|
+
def member(name)
|
59
|
+
h[name]
|
60
|
+
end
|
61
|
+
|
62
|
+
# List of members (Spec::*)
|
63
|
+
def members
|
64
|
+
h.values
|
65
|
+
end
|
66
|
+
|
67
|
+
# List of functions (Spec::Function)
|
68
|
+
def functions
|
69
|
+
members.select {|s| s.kind_of?(Spec::Function) }
|
70
|
+
end
|
71
|
+
|
72
|
+
# List if properties (Spec::Property)
|
73
|
+
def properties
|
74
|
+
members.select {|s| s.kind_of?(Spec::Property) }
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
private
|
79
|
+
def h ; @h ||= {} ; end
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
# Initializes the interface with the given implementer
|
84
|
+
def initialize(*args)
|
85
|
+
@args = args
|
86
|
+
@implementer = Implementer.new(self, *args)
|
87
|
+
end
|
88
|
+
|
89
|
+
|
90
|
+
# Cast to another model
|
91
|
+
def cast(name)
|
92
|
+
@implementer.cast(name, *@args)
|
93
|
+
end
|
94
|
+
|
95
|
+
# Concise inspect
|
96
|
+
def inspect
|
97
|
+
"#<#{self.class.name}>"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
|
102
|
+
end
|
103
|
+
end
|
@@ -2,6 +2,13 @@ module VirtualBox
|
|
2
2
|
module COM
|
3
3
|
|
4
4
|
class IID
|
5
|
+
class FFIStruct < ::FFI::Struct
|
6
|
+
layout :m0, :uint32,
|
7
|
+
:m1, :uint16,
|
8
|
+
:m2, :uint16,
|
9
|
+
:m3, [:uint8, 8]
|
10
|
+
end
|
11
|
+
|
5
12
|
def initialize(obj)
|
6
13
|
@i = case obj
|
7
14
|
when String
|
@@ -37,6 +44,17 @@ class IID
|
|
37
44
|
((@i & 0x000000000000000000000000000000ff) >> 0)]
|
38
45
|
.freeze
|
39
46
|
end
|
47
|
+
|
48
|
+
def to_ffi
|
49
|
+
@ffi ||= begin
|
50
|
+
data = FFIStruct.new
|
51
|
+
data[:m0] = to_a[0]
|
52
|
+
data[:m1] = to_a[1]
|
53
|
+
data[:m2] = to_a[2]
|
54
|
+
to_a[3..-1].each_index{|i| data[:m3][i] = to_a[3..-1][i] }
|
55
|
+
data.freeze
|
56
|
+
end
|
57
|
+
end
|
40
58
|
end
|
41
59
|
|
42
60
|
end
|
@@ -6,6 +6,11 @@ module XPCOMC
|
|
6
6
|
|
7
7
|
|
8
8
|
module Lib
|
9
|
+
SUPPORTED_VERSIONS = {
|
10
|
+
"4.2" => [ "3b2f08eb-b810-4715-bee0-bb06b9880ad2",
|
11
|
+
"12F4DCDB-12B2-4EC1-B7CD-DDD9F6C5BF4D" ]
|
12
|
+
}
|
13
|
+
|
9
14
|
extend ::FFI::Library
|
10
15
|
|
11
16
|
# Constant with default library path and name
|
@@ -71,6 +76,7 @@ module Lib
|
|
71
76
|
next if virtualbox_ptr.null? || session_ptr.null?
|
72
77
|
|
73
78
|
# Load the interface description
|
79
|
+
require "virtualbox/com/model/#{version}-generated"
|
74
80
|
require "virtualbox/com/model/#{version}"
|
75
81
|
|
76
82
|
#
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module VirtualBox
|
2
|
+
module COM
|
3
|
+
|
4
|
+
class IID
|
5
|
+
def initialize(iid)
|
6
|
+
@iid = iid
|
7
|
+
end
|
8
|
+
|
9
|
+
def to_s
|
10
|
+
@iid
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_struct
|
14
|
+
hex = @iid.gsub('-', '')
|
15
|
+
'{' + ([ hex[0,8], hex[8,4], hex[12,4] ].map{|e| "0x#{e}" } +
|
16
|
+
[ '{' + [ hex[16,2], hex[18,2], hex[20,2], hex[22,2],
|
17
|
+
hex[24,2], hex[26,2], hex[28,2], hex[30,2] ]
|
18
|
+
.map{|e| "0x#{e}" }.join(', ') + '}' ]).join(', ') + '}'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class AbstractModel
|
23
|
+
def self.iid(str)
|
24
|
+
const_set(:IID, IID.new(str))
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
def self.nickname
|
29
|
+
self.name.split('::')[-1]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class AbstractInterface < AbstractModel
|
34
|
+
class << self
|
35
|
+
|
36
|
+
# Extends the current model with another one.
|
37
|
+
# Note that redefining functions or properties is not supported.
|
38
|
+
def extends(model = nil)
|
39
|
+
if model.nil?
|
40
|
+
then @model
|
41
|
+
else @model = Model.get(model)
|
42
|
+
end
|
43
|
+
rescue ModelNotFoundException
|
44
|
+
raise "trying to extend an unknown model (#{model})"
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
# Adds a function to the interface
|
49
|
+
def function(name, type, args, opts={})
|
50
|
+
h[name] = Spec::Function.new(name, type, args, opts)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Adds a property to the interface
|
54
|
+
def property(name, type, opts={})
|
55
|
+
h[name] = Spec::Property.new(name, type, opts)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Get a member by name
|
59
|
+
def member(name)
|
60
|
+
h[name]
|
61
|
+
end
|
62
|
+
|
63
|
+
# List of members (Spec::*)
|
64
|
+
def members
|
65
|
+
h.values
|
66
|
+
end
|
67
|
+
|
68
|
+
# List of functions (Spec::Function)
|
69
|
+
def functions
|
70
|
+
members.select {|s| s.kind_of?(Spec::Function) }
|
71
|
+
end
|
72
|
+
|
73
|
+
# List if properties (Spec::Property)
|
74
|
+
def properties
|
75
|
+
members.select {|s| s.kind_of?(Spec::Property) }
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
def h ; @h ||= {} ; end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
end
|
data/scripts/sig.rb
ADDED
@@ -0,0 +1,201 @@
|
|
1
|
+
module VirtualBox
|
2
|
+
module COM
|
3
|
+
|
4
|
+
|
5
|
+
class Sig
|
6
|
+
# Store and normalize signatures
|
7
|
+
def initialize(sig)
|
8
|
+
@sig = sig.map {|item|
|
9
|
+
if item.is_a?(Array) && item[0] == :out
|
10
|
+
then [ item[1], :out ]
|
11
|
+
else [ item, :in ]
|
12
|
+
end
|
13
|
+
}.freeze.each{|type, way|
|
14
|
+
# Sanity check: only `[type]` or `type`
|
15
|
+
if type.is_a?(Array) && type.length != 1
|
16
|
+
raise ArgumentError, "only arrays of simple type are supported"
|
17
|
+
end
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
def size
|
23
|
+
@sig.size
|
24
|
+
end
|
25
|
+
|
26
|
+
def in ; @sig.select {|type, way| way == :in } ; end
|
27
|
+
def out ; @sig.select {|type, way| way == :out } ; end
|
28
|
+
|
29
|
+
def to_c
|
30
|
+
@sig.map {|type, way| is_array = type.is_a?(Array)
|
31
|
+
case way
|
32
|
+
when :out
|
33
|
+
if is_array
|
34
|
+
then [PTR, PTR]
|
35
|
+
else PTR
|
36
|
+
end
|
37
|
+
when :in
|
38
|
+
if is_array then [UINT32, PTR]
|
39
|
+
elsif model = Model.fetch(type)
|
40
|
+
if model <= COM::AbstractInterface then PTR
|
41
|
+
elsif model <= COM::AbstractEnum then UINT32
|
42
|
+
end
|
43
|
+
else type
|
44
|
+
end
|
45
|
+
end
|
46
|
+
}.unshift(PTR).flatten # Add `this` element
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
|
51
|
+
# Enhance signature by adding variable declarations
|
52
|
+
def with_var_decl
|
53
|
+
i = 0
|
54
|
+
@sig.map {|type, way| is_array = type.is_a?(Array)
|
55
|
+
v = "v#{i+=1}"
|
56
|
+
vdecl = if is_array then [["#{v}_size", UINT32], [v, PTR]]
|
57
|
+
elsif model = Model.fetch(type)
|
58
|
+
if model <= AbstractInterface then [[v, PTR]]
|
59
|
+
elsif model <= AbstractEnum then [[v, UINT32]]
|
60
|
+
end
|
61
|
+
else [[v, type]]
|
62
|
+
end
|
63
|
+
[type, way] + vdecl
|
64
|
+
}
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
|
69
|
+
|
70
|
+
|
71
|
+
|
72
|
+
def to_c_func(name, vtbl, fun)
|
73
|
+
ins = self.in;
|
74
|
+
|
75
|
+
args= ([ 'self' ] + ins.size.times.map {|i| "i#{i}"})
|
76
|
+
.map {|v| "VALUE #{v}"}.join(', ')
|
77
|
+
|
78
|
+
OUT << "static VALUE #{name}(#{args}) {\n"
|
79
|
+
OUT << " VALUE res = Qundef;\n"
|
80
|
+
OUT << " struct obj *obj = DATA_PTR(self);\n"
|
81
|
+
OUT << " struct #{vtbl} *vtbl = obj->vtbl;\n"
|
82
|
+
|
83
|
+
args = self.with_var_decl
|
84
|
+
|
85
|
+
args.each{|type, way, *vdecl|
|
86
|
+
vdecl.each{|var, decl|
|
87
|
+
OUT << " #{decl} #{var};\n"
|
88
|
+
}
|
89
|
+
}
|
90
|
+
|
91
|
+
ins.each_index{|i| type, = ins[i]
|
92
|
+
OUT << " i#{i} = " << do_prepare(type, "i#{i}") << ";\n"
|
93
|
+
}
|
94
|
+
|
95
|
+
i = 0;
|
96
|
+
args.each {|type, way, *vdec| is_array = type.is_a?(Array)
|
97
|
+
if way == :in
|
98
|
+
OUT << " " << get_extract(type, "i#{i}", vdec.map{|var, dec|
|
99
|
+
"&#{var}"}) << ";\n"
|
100
|
+
end
|
101
|
+
i += 1
|
102
|
+
}
|
103
|
+
|
104
|
+
a = args.map {|type, way, *vdec| vdec.map{|var, dec|
|
105
|
+
if way == :out then "&#{var}" else var end } }.flatten
|
106
|
+
a.unshift('obj');
|
107
|
+
OUT << " NS_CHECK(vtbl->#{fun}(" << a.join(', ') << "));\n"
|
108
|
+
|
109
|
+
|
110
|
+
|
111
|
+
OUT << " res = rb_ary_new();\n"
|
112
|
+
i = 0
|
113
|
+
o = 0
|
114
|
+
args.each {|type, way, *vdec| is_array = type.is_a?(Array)
|
115
|
+
if way == :out
|
116
|
+
OUT << " rb_ary_push(res, " << get_convert(type, vdec.map{|var, dec|
|
117
|
+
"#{var}"}) << ");\n"
|
118
|
+
o += 1
|
119
|
+
end
|
120
|
+
i += 1
|
121
|
+
}
|
122
|
+
|
123
|
+
OUT << " res = rb_ary_entry(res, 0);\n" if o == 1
|
124
|
+
OUT << " return res;\n"
|
125
|
+
OUT << "}\n"
|
126
|
+
|
127
|
+
end
|
128
|
+
|
129
|
+
|
130
|
+
|
131
|
+
def get_convert(type, *args)
|
132
|
+
is_array = type.is_a?(Array)
|
133
|
+
type = type[0] if is_array
|
134
|
+
|
135
|
+
m, *a = to_converter(type)
|
136
|
+
m = "array_#{m}" if is_array && type != OCTET
|
137
|
+
m = "convert_#{m}"
|
138
|
+
m + '(' + (args + a).join(', ') + ')'
|
139
|
+
end
|
140
|
+
|
141
|
+
def get_extract(type, src, *args)
|
142
|
+
is_array = type.is_a?(Array)
|
143
|
+
type = type[0] if is_array
|
144
|
+
a = []
|
145
|
+
|
146
|
+
if is_array && type == OCTET
|
147
|
+
m = :blob
|
148
|
+
elsif is_array
|
149
|
+
m = :carray
|
150
|
+
else
|
151
|
+
m, *a = to_converter(type)
|
152
|
+
end
|
153
|
+
m = "extract_#{m}"
|
154
|
+
m + '(' + ([src] + args + a).join(', ') + ')'
|
155
|
+
end
|
156
|
+
|
157
|
+
def get_in_and_out(prefix, type, src, *args)
|
158
|
+
end
|
159
|
+
|
160
|
+
def do_prepare(type, src)
|
161
|
+
is_array = type.is_a?(Array)
|
162
|
+
type = type[0] if is_array
|
163
|
+
|
164
|
+
m, *a = to_converter(type)
|
165
|
+
m = "array_#{m}" if is_array && type != OCTET
|
166
|
+
m = "prepare_#{m}"
|
167
|
+
m + '(' + ([src] + a).join(', ') + ')'
|
168
|
+
end
|
169
|
+
|
170
|
+
|
171
|
+
|
172
|
+
def to_converter(type)
|
173
|
+
is_array = type.is_a?(Array)
|
174
|
+
type = type[0] if is_array
|
175
|
+
|
176
|
+
case type
|
177
|
+
when BOOL then :bool
|
178
|
+
when PTR then :ptr
|
179
|
+
when OCTET then :blob
|
180
|
+
when INT16 then :int16
|
181
|
+
when INT32 then :int32
|
182
|
+
when INT64 then :int64
|
183
|
+
when UINT16 then :uint16
|
184
|
+
when UINT32 then :uint32
|
185
|
+
when UINT64 then :uint64
|
186
|
+
when WSTRING then :wstring
|
187
|
+
else
|
188
|
+
if model = Model.fetch(type)
|
189
|
+
kind = if model <= AbstractInterface then :interface
|
190
|
+
elsif model <= AbstractEnum then :enum
|
191
|
+
else raise "unknown model #{mode.class}"
|
192
|
+
end
|
193
|
+
[ kind, "c#{type}" ]
|
194
|
+
else raise "unknown type #{type}"
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
end
|
201
|
+
end
|