bbrowning-virtualbox 0.7.6.dev

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.
Files changed (281) hide show
  1. data/.gitignore +8 -0
  2. data/.yardopts +3 -0
  3. data/Gemfile +16 -0
  4. data/LICENSE +19 -0
  5. data/Rakefile +33 -0
  6. data/Readme.md +70 -0
  7. data/docs/GettingStarted.md +196 -0
  8. data/docs/WhatsNew.md +12 -0
  9. data/features/README.md +33 -0
  10. data/features/global.feature +19 -0
  11. data/features/global_extra_data.feature +27 -0
  12. data/features/step_definitions/abstract_model_steps.rb +39 -0
  13. data/features/step_definitions/extra_data_steps.rb +36 -0
  14. data/features/step_definitions/global_steps.rb +29 -0
  15. data/features/step_definitions/nat_engine_steps.rb +76 -0
  16. data/features/step_definitions/network_adapter_steps.rb +38 -0
  17. data/features/step_definitions/shared_folder_steps.rb +76 -0
  18. data/features/step_definitions/snapshot_steps.rb +74 -0
  19. data/features/step_definitions/storage_controller_steps.rb +16 -0
  20. data/features/step_definitions/virtualbox_steps.rb +17 -0
  21. data/features/step_definitions/vm_steps.rb +50 -0
  22. data/features/support/env.rb +61 -0
  23. data/features/support/helpers.rb +38 -0
  24. data/features/support/hooks.rb +30 -0
  25. data/features/support/ordered_hash.rb +49 -0
  26. data/features/support/vboxmanage.rb +191 -0
  27. data/features/version.feature +16 -0
  28. data/features/vm.feature +13 -0
  29. data/features/vm_bios.feature +29 -0
  30. data/features/vm_cpu.feature +29 -0
  31. data/features/vm_extra_data.feature +35 -0
  32. data/features/vm_hw_virt.feature +29 -0
  33. data/features/vm_nat_engine.feature +57 -0
  34. data/features/vm_network_adapters.feature +27 -0
  35. data/features/vm_shared_folders.feature +42 -0
  36. data/features/vm_snapshots.feature +29 -0
  37. data/features/vm_storage_controllers.feature +11 -0
  38. data/lib/virtualbox.rb +11 -0
  39. data/lib/virtualbox/abstract_model.rb +281 -0
  40. data/lib/virtualbox/abstract_model/attributable.rb +290 -0
  41. data/lib/virtualbox/abstract_model/dirty.rb +177 -0
  42. data/lib/virtualbox/abstract_model/interface_attributes.rb +98 -0
  43. data/lib/virtualbox/abstract_model/relatable.rb +332 -0
  44. data/lib/virtualbox/abstract_model/validatable.rb +167 -0
  45. data/lib/virtualbox/abstract_model/version_matcher.rb +35 -0
  46. data/lib/virtualbox/appliance.rb +62 -0
  47. data/lib/virtualbox/audio_adapter.rb +52 -0
  48. data/lib/virtualbox/bios.rb +50 -0
  49. data/lib/virtualbox/com.rb +23 -0
  50. data/lib/virtualbox/com/abstract_enum.rb +43 -0
  51. data/lib/virtualbox/com/abstract_implementer.rb +45 -0
  52. data/lib/virtualbox/com/abstract_interface.rb +167 -0
  53. data/lib/virtualbox/com/base_interface.rb +38 -0
  54. data/lib/virtualbox/com/ffi/interface.rb +150 -0
  55. data/lib/virtualbox/com/ffi/interfaces.rb +54 -0
  56. data/lib/virtualbox/com/ffi/util.rb +119 -0
  57. data/lib/virtualbox/com/ffi/vboxxpcomc.rb +31 -0
  58. data/lib/virtualbox/com/ffi_interface.rb +96 -0
  59. data/lib/virtualbox/com/implementer/base.rb +59 -0
  60. data/lib/virtualbox/com/implementer/ffi.rb +361 -0
  61. data/lib/virtualbox/com/implementer/mscom.rb +175 -0
  62. data/lib/virtualbox/com/implementer/nil.rb +10 -0
  63. data/lib/virtualbox/com/interface/3.1.x/access_mode.rb +11 -0
  64. data/lib/virtualbox/com/interface/3.1.x/appliance.rb +22 -0
  65. data/lib/virtualbox/com/interface/3.1.x/audio_adapter.rb +15 -0
  66. data/lib/virtualbox/com/interface/3.1.x/audio_controller_type.rb +11 -0
  67. data/lib/virtualbox/com/interface/3.1.x/audio_driver_type.rb +11 -0
  68. data/lib/virtualbox/com/interface/3.1.x/bios_boot_menu_mode.rb +11 -0
  69. data/lib/virtualbox/com/interface/3.1.x/bios_settings.rb +21 -0
  70. data/lib/virtualbox/com/interface/3.1.x/clipboard_mode.rb +11 -0
  71. data/lib/virtualbox/com/interface/3.1.x/console.rb +50 -0
  72. data/lib/virtualbox/com/interface/3.1.x/cpu_property_type.rb +11 -0
  73. data/lib/virtualbox/com/interface/3.1.x/device_type.rb +11 -0
  74. data/lib/virtualbox/com/interface/3.1.x/dhcp_server.rb +22 -0
  75. data/lib/virtualbox/com/interface/3.1.x/firmware_type.rb +11 -0
  76. data/lib/virtualbox/com/interface/3.1.x/guest_os_type.rb +23 -0
  77. data/lib/virtualbox/com/interface/3.1.x/host.rb +42 -0
  78. data/lib/virtualbox/com/interface/3.1.x/host_network_interface.rb +30 -0
  79. data/lib/virtualbox/com/interface/3.1.x/host_network_interface_medium_type.rb +11 -0
  80. data/lib/virtualbox/com/interface/3.1.x/host_network_interface_status.rb +11 -0
  81. data/lib/virtualbox/com/interface/3.1.x/host_network_interface_type.rb +11 -0
  82. data/lib/virtualbox/com/interface/3.1.x/host_usb_device.rb +13 -0
  83. data/lib/virtualbox/com/interface/3.1.x/host_usb_device_filter.rb +13 -0
  84. data/lib/virtualbox/com/interface/3.1.x/hw_virt_ex_property_type.rb +11 -0
  85. data/lib/virtualbox/com/interface/3.1.x/machine.rb +105 -0
  86. data/lib/virtualbox/com/interface/3.1.x/machine_state.rb +14 -0
  87. data/lib/virtualbox/com/interface/3.1.x/medium.rb +50 -0
  88. data/lib/virtualbox/com/interface/3.1.x/medium_attachment.rb +18 -0
  89. data/lib/virtualbox/com/interface/3.1.x/medium_format.rb +18 -0
  90. data/lib/virtualbox/com/interface/3.1.x/medium_state.rb +11 -0
  91. data/lib/virtualbox/com/interface/3.1.x/medium_type.rb +11 -0
  92. data/lib/virtualbox/com/interface/3.1.x/medium_variant.rb +11 -0
  93. data/lib/virtualbox/com/interface/3.1.x/network_adapter.rb +30 -0
  94. data/lib/virtualbox/com/interface/3.1.x/network_adapter_type.rb +11 -0
  95. data/lib/virtualbox/com/interface/3.1.x/network_attachment_type.rb +11 -0
  96. data/lib/virtualbox/com/interface/3.1.x/nsiexception.rb +23 -0
  97. data/lib/virtualbox/com/interface/3.1.x/nsisupports.rb +15 -0
  98. data/lib/virtualbox/com/interface/3.1.x/parallel_port.rb +17 -0
  99. data/lib/virtualbox/com/interface/3.1.x/port_mode.rb +11 -0
  100. data/lib/virtualbox/com/interface/3.1.x/progress.rb +63 -0
  101. data/lib/virtualbox/com/interface/3.1.x/serial_port.rb +19 -0
  102. data/lib/virtualbox/com/interface/3.1.x/session.rb +18 -0
  103. data/lib/virtualbox/com/interface/3.1.x/session_state.rb +11 -0
  104. data/lib/virtualbox/com/interface/3.1.x/session_type.rb +11 -0
  105. data/lib/virtualbox/com/interface/3.1.x/shared_folder.rb +17 -0
  106. data/lib/virtualbox/com/interface/3.1.x/snapshot.rb +20 -0
  107. data/lib/virtualbox/com/interface/3.1.x/storage_bus.rb +11 -0
  108. data/lib/virtualbox/com/interface/3.1.x/storage_controller.rb +23 -0
  109. data/lib/virtualbox/com/interface/3.1.x/storage_controller_type.rb +11 -0
  110. data/lib/virtualbox/com/interface/3.1.x/system_properties.rb +37 -0
  111. data/lib/virtualbox/com/interface/3.1.x/usb_controller.rb +20 -0
  112. data/lib/virtualbox/com/interface/3.1.x/usb_device.rb +24 -0
  113. data/lib/virtualbox/com/interface/3.1.x/usb_device_filter.rb +23 -0
  114. data/lib/virtualbox/com/interface/3.1.x/usb_device_filter_action.rb +11 -0
  115. data/lib/virtualbox/com/interface/3.1.x/usb_device_state.rb +11 -0
  116. data/lib/virtualbox/com/interface/3.1.x/virtual_box_error_info.rb +17 -0
  117. data/lib/virtualbox/com/interface/3.1.x/virtual_system_description.rb +19 -0
  118. data/lib/virtualbox/com/interface/3.1.x/virtual_system_description_type.rb +14 -0
  119. data/lib/virtualbox/com/interface/3.1.x/virtual_system_description_value_type.rb +11 -0
  120. data/lib/virtualbox/com/interface/3.1.x/virtualbox.rb +67 -0
  121. data/lib/virtualbox/com/interface/3.1.x/vrdp_auth_type.rb +11 -0
  122. data/lib/virtualbox/com/interface/3.1.x/vrdp_server.rb +19 -0
  123. data/lib/virtualbox/com/interface/3.2.x/access_mode.rb +11 -0
  124. data/lib/virtualbox/com/interface/3.2.x/appliance.rb +22 -0
  125. data/lib/virtualbox/com/interface/3.2.x/audio_adapter.rb +15 -0
  126. data/lib/virtualbox/com/interface/3.2.x/audio_controller_type.rb +11 -0
  127. data/lib/virtualbox/com/interface/3.2.x/audio_driver_type.rb +11 -0
  128. data/lib/virtualbox/com/interface/3.2.x/bios_boot_menu_mode.rb +11 -0
  129. data/lib/virtualbox/com/interface/3.2.x/bios_settings.rb +21 -0
  130. data/lib/virtualbox/com/interface/3.2.x/clipboard_mode.rb +11 -0
  131. data/lib/virtualbox/com/interface/3.2.x/console.rb +50 -0
  132. data/lib/virtualbox/com/interface/3.2.x/cpu_property_type.rb +11 -0
  133. data/lib/virtualbox/com/interface/3.2.x/device_type.rb +11 -0
  134. data/lib/virtualbox/com/interface/3.2.x/dhcp_server.rb +22 -0
  135. data/lib/virtualbox/com/interface/3.2.x/firmware_type.rb +11 -0
  136. data/lib/virtualbox/com/interface/3.2.x/guest.rb +13 -0
  137. data/lib/virtualbox/com/interface/3.2.x/guest_os_type.rb +33 -0
  138. data/lib/virtualbox/com/interface/3.2.x/host.rb +43 -0
  139. data/lib/virtualbox/com/interface/3.2.x/host_network_interface.rb +30 -0
  140. data/lib/virtualbox/com/interface/3.2.x/host_network_interface_medium_type.rb +11 -0
  141. data/lib/virtualbox/com/interface/3.2.x/host_network_interface_status.rb +11 -0
  142. data/lib/virtualbox/com/interface/3.2.x/host_network_interface_type.rb +11 -0
  143. data/lib/virtualbox/com/interface/3.2.x/host_usb_device.rb +13 -0
  144. data/lib/virtualbox/com/interface/3.2.x/host_usb_device_filter.rb +13 -0
  145. data/lib/virtualbox/com/interface/3.2.x/hw_virt_ex_property_type.rb +11 -0
  146. data/lib/virtualbox/com/interface/3.2.x/keyboard_hid_type.rb +11 -0
  147. data/lib/virtualbox/com/interface/3.2.x/machine.rb +118 -0
  148. data/lib/virtualbox/com/interface/3.2.x/machine_state.rb +14 -0
  149. data/lib/virtualbox/com/interface/3.2.x/medium.rb +51 -0
  150. data/lib/virtualbox/com/interface/3.2.x/medium_attachment.rb +18 -0
  151. data/lib/virtualbox/com/interface/3.2.x/medium_format.rb +18 -0
  152. data/lib/virtualbox/com/interface/3.2.x/medium_state.rb +11 -0
  153. data/lib/virtualbox/com/interface/3.2.x/medium_type.rb +11 -0
  154. data/lib/virtualbox/com/interface/3.2.x/medium_variant.rb +11 -0
  155. data/lib/virtualbox/com/interface/3.2.x/nat_alias_mode.rb +11 -0
  156. data/lib/virtualbox/com/interface/3.2.x/nat_engine.rb +27 -0
  157. data/lib/virtualbox/com/interface/3.2.x/nat_protocol.rb +11 -0
  158. data/lib/virtualbox/com/interface/3.2.x/network_adapter.rb +34 -0
  159. data/lib/virtualbox/com/interface/3.2.x/network_adapter_type.rb +11 -0
  160. data/lib/virtualbox/com/interface/3.2.x/network_attachment_type.rb +11 -0
  161. data/lib/virtualbox/com/interface/3.2.x/nsiexception.rb +23 -0
  162. data/lib/virtualbox/com/interface/3.2.x/nsisupports.rb +15 -0
  163. data/lib/virtualbox/com/interface/3.2.x/parallel_port.rb +17 -0
  164. data/lib/virtualbox/com/interface/3.2.x/pointing_hid_type.rb +11 -0
  165. data/lib/virtualbox/com/interface/3.2.x/port_mode.rb +11 -0
  166. data/lib/virtualbox/com/interface/3.2.x/progress.rb +63 -0
  167. data/lib/virtualbox/com/interface/3.2.x/serial_port.rb +19 -0
  168. data/lib/virtualbox/com/interface/3.2.x/session.rb +18 -0
  169. data/lib/virtualbox/com/interface/3.2.x/session_state.rb +11 -0
  170. data/lib/virtualbox/com/interface/3.2.x/session_type.rb +11 -0
  171. data/lib/virtualbox/com/interface/3.2.x/shared_folder.rb +17 -0
  172. data/lib/virtualbox/com/interface/3.2.x/snapshot.rb +20 -0
  173. data/lib/virtualbox/com/interface/3.2.x/storage_bus.rb +11 -0
  174. data/lib/virtualbox/com/interface/3.2.x/storage_controller.rb +24 -0
  175. data/lib/virtualbox/com/interface/3.2.x/storage_controller_type.rb +11 -0
  176. data/lib/virtualbox/com/interface/3.2.x/system_properties.rb +42 -0
  177. data/lib/virtualbox/com/interface/3.2.x/usb_controller.rb +21 -0
  178. data/lib/virtualbox/com/interface/3.2.x/usb_device.rb +24 -0
  179. data/lib/virtualbox/com/interface/3.2.x/usb_device_filter.rb +23 -0
  180. data/lib/virtualbox/com/interface/3.2.x/usb_device_filter_action.rb +11 -0
  181. data/lib/virtualbox/com/interface/3.2.x/usb_device_state.rb +11 -0
  182. data/lib/virtualbox/com/interface/3.2.x/virtual_box_error_info.rb +17 -0
  183. data/lib/virtualbox/com/interface/3.2.x/virtual_system_description.rb +19 -0
  184. data/lib/virtualbox/com/interface/3.2.x/virtual_system_description_type.rb +14 -0
  185. data/lib/virtualbox/com/interface/3.2.x/virtual_system_description_value_type.rb +11 -0
  186. data/lib/virtualbox/com/interface/3.2.x/virtualbox.rb +67 -0
  187. data/lib/virtualbox/com/interface/3.2.x/vrdp_auth_type.rb +11 -0
  188. data/lib/virtualbox/com/interface/3.2.x/vrdp_server.rb +21 -0
  189. data/lib/virtualbox/com/mscom_interface.rb +44 -0
  190. data/lib/virtualbox/com/nil_interface.rb +7 -0
  191. data/lib/virtualbox/com/util.rb +32 -0
  192. data/lib/virtualbox/cpu.rb +61 -0
  193. data/lib/virtualbox/dhcp_server.rb +89 -0
  194. data/lib/virtualbox/dvd.rb +27 -0
  195. data/lib/virtualbox/exceptions.rb +39 -0
  196. data/lib/virtualbox/ext/byte_normalizer.rb +17 -0
  197. data/lib/virtualbox/ext/glob_loader.rb +22 -0
  198. data/lib/virtualbox/ext/logger.rb +38 -0
  199. data/lib/virtualbox/ext/platform.rb +27 -0
  200. data/lib/virtualbox/ext/subclass_listing.rb +24 -0
  201. data/lib/virtualbox/extra_data.rb +127 -0
  202. data/lib/virtualbox/forwarded_port.rb +222 -0
  203. data/lib/virtualbox/global.rb +102 -0
  204. data/lib/virtualbox/guest_property.rb +116 -0
  205. data/lib/virtualbox/hard_drive.rb +246 -0
  206. data/lib/virtualbox/host.rb +71 -0
  207. data/lib/virtualbox/host_network_interface.rb +137 -0
  208. data/lib/virtualbox/hw_virtualization.rb +63 -0
  209. data/lib/virtualbox/lib.rb +84 -0
  210. data/lib/virtualbox/media.rb +20 -0
  211. data/lib/virtualbox/medium.rb +145 -0
  212. data/lib/virtualbox/medium_attachment.rb +61 -0
  213. data/lib/virtualbox/nat_engine.rb +71 -0
  214. data/lib/virtualbox/nat_forwarded_port.rb +171 -0
  215. data/lib/virtualbox/network_adapter.rb +166 -0
  216. data/lib/virtualbox/proxies/collection.rb +57 -0
  217. data/lib/virtualbox/shared_folder.rb +220 -0
  218. data/lib/virtualbox/snapshot.rb +185 -0
  219. data/lib/virtualbox/storage_controller.rb +160 -0
  220. data/lib/virtualbox/system_properties.rb +74 -0
  221. data/lib/virtualbox/usb_controller.rb +59 -0
  222. data/lib/virtualbox/usb_device_filter.rb +74 -0
  223. data/lib/virtualbox/version.rb +36 -0
  224. data/lib/virtualbox/virtual_system_description.rb +47 -0
  225. data/lib/virtualbox/vm.rb +684 -0
  226. data/lib/virtualbox/vrdp_server.rb +59 -0
  227. data/test/test_helper.rb +18 -0
  228. data/test/virtualbox/abstract_model/attributable_test.rb +269 -0
  229. data/test/virtualbox/abstract_model/dirty_test.rb +83 -0
  230. data/test/virtualbox/abstract_model/interface_attributes_test.rb +194 -0
  231. data/test/virtualbox/abstract_model/relatable_test.rb +348 -0
  232. data/test/virtualbox/abstract_model/validatable_test.rb +308 -0
  233. data/test/virtualbox/abstract_model/version_matcher_test.rb +41 -0
  234. data/test/virtualbox/abstract_model_test.rb +462 -0
  235. data/test/virtualbox/appliance_test.rb +159 -0
  236. data/test/virtualbox/audio_adapter_test.rb +83 -0
  237. data/test/virtualbox/bios_test.rb +83 -0
  238. data/test/virtualbox/com/abstract_enum_test.rb +49 -0
  239. data/test/virtualbox/com/abstract_implementer_test.rb +40 -0
  240. data/test/virtualbox/com/abstract_interface_test.rb +140 -0
  241. data/test/virtualbox/com/ffi/interface_test.rb +249 -0
  242. data/test/virtualbox/com/ffi/util_test.rb +108 -0
  243. data/test/virtualbox/com/ffi_interface_test.rb +42 -0
  244. data/test/virtualbox/com/implementer/base_test.rb +38 -0
  245. data/test/virtualbox/com/implementer/ffi_test.rb +527 -0
  246. data/test/virtualbox/com/implementer/mscom_test.rb +247 -0
  247. data/test/virtualbox/com/mscom_interface_test.rb +17 -0
  248. data/test/virtualbox/com/util_test.rb +17 -0
  249. data/test/virtualbox/cpu_test.rb +103 -0
  250. data/test/virtualbox/dhcp_server_test.rb +165 -0
  251. data/test/virtualbox/dvd_test.rb +28 -0
  252. data/test/virtualbox/ext/byte_normalizer_test.rb +34 -0
  253. data/test/virtualbox/ext/platform_test.rb +50 -0
  254. data/test/virtualbox/ext/subclass_listing_test.rb +25 -0
  255. data/test/virtualbox/extra_data_test.rb +155 -0
  256. data/test/virtualbox/forwarded_port_test.rb +286 -0
  257. data/test/virtualbox/global_test.rb +46 -0
  258. data/test/virtualbox/hard_drive_test.rb +141 -0
  259. data/test/virtualbox/host_network_interface_test.rb +254 -0
  260. data/test/virtualbox/host_test.rb +94 -0
  261. data/test/virtualbox/hw_virtualization_test.rb +103 -0
  262. data/test/virtualbox/lib_test.rb +93 -0
  263. data/test/virtualbox/medium_attachment_test.rb +147 -0
  264. data/test/virtualbox/medium_test.rb +192 -0
  265. data/test/virtualbox/nat_engine_test.rb +106 -0
  266. data/test/virtualbox/nat_forwarded_port_test.rb +222 -0
  267. data/test/virtualbox/network_adapter_test.rb +191 -0
  268. data/test/virtualbox/proxies/collection_test.rb +102 -0
  269. data/test/virtualbox/shared_folder_test.rb +219 -0
  270. data/test/virtualbox/snapshot_test.rb +231 -0
  271. data/test/virtualbox/storage_controller_test.rb +197 -0
  272. data/test/virtualbox/system_properties_test.rb +87 -0
  273. data/test/virtualbox/usb_controller_test.rb +112 -0
  274. data/test/virtualbox/usb_device_filter_test.rb +93 -0
  275. data/test/virtualbox/version_test.rb +59 -0
  276. data/test/virtualbox/virtual_system_description_test.rb +61 -0
  277. data/test/virtualbox/vm_test.rb +637 -0
  278. data/test/virtualbox/vrdp_server_test.rb +83 -0
  279. data/test/virtualbox_test.rb +11 -0
  280. data/virtualbox.gemspec +25 -0
  281. metadata +397 -0
@@ -0,0 +1,59 @@
1
+ module VirtualBox
2
+ module COM
3
+ module Implementer
4
+ class Base < AbstractImplementer
5
+ include Logger
6
+
7
+ # Returns the Ruby version as a float
8
+ #
9
+ # @return [Float]
10
+ def ruby_version
11
+ RUBY_VERSION.to_f
12
+ end
13
+
14
+ # Finds and returns the `COM::Interface` class associated with the type.
15
+ # If the class does not exist, a `NameError` will be raised.
16
+ #
17
+ # @return [Class]
18
+ def interface_klass(type)
19
+ ::VirtualBox::COM::FFI::Util.interface_klass(type)
20
+ end
21
+
22
+ # Gives the C type and inferred type of a parameter type. Quite confusing
23
+ # since the terminology is not consistent, but hopefully these examples
24
+ # will help:
25
+ #
26
+ # type => [pointer_type, internal_type]
27
+ # :int => [:int, :int]
28
+ # :MyStruct => [:pointer, :struct]
29
+ # :unicode_string => [:pointer, :unicode_string]
30
+ #
31
+ def infer_type(type)
32
+ c_type = type
33
+
34
+ begin
35
+ if type == WSTRING
36
+ # Handle strings as pointer types
37
+ c_type = :pointer
38
+ else
39
+ # Try to get the class from the interfaces
40
+ interface = interface_klass(type)
41
+
42
+ c_type = :pointer
43
+
44
+ # Depending on the class type, we're either dealing with an interface
45
+ # or an enum
46
+ type = :interface if interface.superclass == COM::AbstractInterface
47
+ type = :enum if interface.superclass == COM::AbstractEnum
48
+ end
49
+ rescue NameError
50
+ # Do nothing
51
+ end
52
+
53
+ [c_type, type]
54
+ end
55
+
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,361 @@
1
+ module VirtualBox
2
+ module COM
3
+ module Implementer
4
+ class FFI < Base
5
+ attr_reader :ffi_interface
6
+
7
+ # Initializes the FFI implementer which takes an {VirtualBox::COM::AbstractInterface AbstractInterface}
8
+ # instant and FFI pointer and initializes everything required to
9
+ # communicate with that interface via FFI.
10
+ #
11
+ # @param [VirtualBox::COM::AbstractInteface] inteface
12
+ # @param [FFI::Pointer] pointer
13
+ def initialize(interface, lib_base, pointer)
14
+ super(interface, lib_base)
15
+
16
+ @ffi_interface = ffi_class.new(pointer)
17
+ end
18
+
19
+ # Gets the FFI struct class associated with the interface. This works
20
+ # by stripping the namespace off of the interface class and finding that
21
+ # same class within the `COM::FFI` namespace. For example:
22
+ # `VirtualBox::COM::Interface::Session` becomes `VirtualBox::COM::FFI::Session`
23
+ #
24
+ # @return [Class]
25
+ def ffi_class
26
+ # Take off the last part of the class, so `Foo::Bar::Baz` becomes
27
+ # just `Baz`
28
+ klass_name = interface.class.to_s.split("::").last
29
+
30
+ # Get the associated FFI class
31
+ COM::FFI.const_get(::VirtualBox::COM::Util.version_const).const_get(klass_name)
32
+ end
33
+
34
+ # Reads a property from the interface with the given name.
35
+ def read_property(name, opts)
36
+ call_vtbl_function("get_#{name}".to_sym, [[:out, opts[:value_type]]])
37
+ end
38
+
39
+ # Writes a property to the interface with the given name and value.
40
+ def write_property(name, value, opts)
41
+ call_vtbl_function("set_#{name}".to_sym, [opts[:value_type]], [value])
42
+ end
43
+
44
+ # Calls a function from the interface with the given name and args. This
45
+ # method is called from the {AbstractInterface}.
46
+ def call_function(name, args, opts)
47
+ spec = opts[:spec].dup
48
+ spec << [:out, opts[:value_type]] if !opts[:value_type].nil?
49
+
50
+ call_vtbl_function(name.to_sym, spec, args)
51
+ end
52
+
53
+ # Calls a function on the vtbl of the FFI struct. This function handles
54
+ # converting the spec to proper arguments and also handles reading out
55
+ # the arguments, dereferencing pointers, setting up objects, etc. so that
56
+ # the return value is filled with nicely formatted Ruby objects.
57
+ #
58
+ # If the vtbl function being called only has one out parameter, then the
59
+ # return value will be that single object. If it has multiple, then it will
60
+ # be an array of objects.
61
+ def call_vtbl_function(name, spec, args=[])
62
+ # Get the "formal argument" list. This is the list of arguments to send
63
+ # to the actual function based on the spec. This contains pointers, some
64
+ # arguments from `args`, etc.
65
+ formal_args = spec_to_args(spec, args)
66
+
67
+ # Call the function.
68
+ logger.debug("FFI call: #{name} #{args.inspect} #{formal_args.inspect}")
69
+ call_and_check(name, ffi_interface.vtbl_parent, *formal_args)
70
+
71
+ # Extract the values from the formal args array, again based on the
72
+ # spec (and the various :out parameters)
73
+ result = values_from_formal_args(spec, formal_args)
74
+ logger.debug(" = #{result.inspect}")
75
+ result
76
+ end
77
+
78
+ #############################################################
79
+ # Internal Methods, a.k.a. unless you're hacking on the code of this
80
+ # library, you should do well to leave these alone =]
81
+ #############################################################
82
+
83
+ # Checks the result of a method call for an error, and if an error
84
+ # occurs, then raises an exception.
85
+ def call_and_check(function, *args)
86
+ result = ffi_interface.vtbl[function].call(*args)
87
+
88
+ # Ignore NS_ERROR_NOT_IMPLEMENTED, since it seems to be raised for
89
+ # things which aren't really exceptional
90
+ if result != 2147500033 && (result & 0x8000_0000) != 0
91
+ # Failure, raise exception with details of the error
92
+ raise exception_map(result).new({
93
+ :function => function.to_s,
94
+ :result_code => result
95
+ })
96
+ end
97
+ end
98
+
99
+ # Maps a result code to an exception. If no mapping currently exists,
100
+ # then a regular {Exceptions::FFIException} is returned.
101
+ #
102
+ # @param [Fixnum] code Result code
103
+ # @return [Class]
104
+ def exception_map(code)
105
+ map = {
106
+ 0x80BB_0001 => Exceptions::ObjectNotFoundException,
107
+ 0x80BB_0002 => Exceptions::InvalidVMStateException,
108
+ 0x80BB_0003 => Exceptions::VMErrorException,
109
+ 0x80BB_0004 => Exceptions::FileErrorException,
110
+ 0x80BB_0005 => Exceptions::SubsystemException,
111
+ 0x80BB_0006 => Exceptions::PDMException,
112
+ 0x80BB_0007 => Exceptions::InvalidObjectStateException,
113
+ 0x80BB_0008 => Exceptions::HostErrorException,
114
+ 0x80BB_0009 => Exceptions::NotSupportedException,
115
+ 0x80BB_000A => Exceptions::XMLErrorException,
116
+ 0x80BB_000B => Exceptions::InvalidSessionStateException,
117
+ 0x80BB_000C => Exceptions::ObjectInUseException
118
+ }
119
+
120
+ map[code] || Exceptions::FFIException
121
+ end
122
+
123
+ # Converts a function spec to a proper argument list with the given
124
+ # arguments.
125
+ #
126
+ # @return [Array]
127
+ def spec_to_args(spec, args=[])
128
+ args = args.dup
129
+
130
+ results = spec.inject([]) do |results, item|
131
+ single_type_to_arg(args, item, results)
132
+ end
133
+ end
134
+
135
+ # Converts a single type and args list to the proper formal args list
136
+ def single_type_to_arg(args, item, results)
137
+ if item.is_a?(Array) && item[0] == :out
138
+ if item[1].is_a?(Array)
139
+ # For arrays we need two pointers: one for size, and one for the
140
+ # actual array
141
+ results << pointer_for_type(T_UINT32)
142
+ results << pointer_for_type(item[1][0])
143
+ else
144
+ results << pointer_for_type(item[1])
145
+ end
146
+ elsif item.is_a?(Array) && item.length == 1
147
+ # Convert the array to a size, then array parameter
148
+ data = args.shift
149
+ results << data.length
150
+ results << data.inject([]) do |converted_data, single|
151
+ single_type_to_arg([single], item[0], converted_data)
152
+ end
153
+ elsif item == WSTRING
154
+ # We have to convert the arg to a unicode string
155
+ results << string_to_utf16(args.shift)
156
+ elsif item == T_BOOL
157
+ results << (args.shift ? 1 : 0)
158
+ elsif item.to_s[0,1] == item.to_s[0,1].upcase
159
+ # Try to get the class from the interfaces
160
+ interface = interface_klass(item.to_sym)
161
+
162
+ if interface.superclass == COM::AbstractInterface
163
+ # For interfaces, get the instance, then dig deep to get the pointer
164
+ # to the VtblParent, which is what the API expects
165
+ instance = args.shift
166
+
167
+ results << if !instance.nil?
168
+ instance.implementer.ffi_interface.vtbl_parent
169
+ else
170
+ # If the argument was nil, just pass a nil pointer as the argument
171
+ nil
172
+ end
173
+ elsif interface.superclass == COM::AbstractEnum
174
+ # For enums, we need the value of the enum
175
+ results << interface.index(args.shift.to_sym)
176
+ end
177
+ else
178
+ # Simply replace spec item with next item in args
179
+ # list
180
+ results << args.shift
181
+ end
182
+ end
183
+
184
+ # Takes a spec and a formal parameter list and returns the output from
185
+ # a function, properly dereferencing any output pointers.
186
+ #
187
+ # @param [Array] specs The parameter spec for the function
188
+ # @param [Array] formal The formal parameter list
189
+ def values_from_formal_args(specs, formal)
190
+ return_values = []
191
+ i = 0
192
+ specs.each do |spec|
193
+ # Output parameters are all we care about
194
+ if spec.is_a?(Array) && spec[0] == :out
195
+ if spec[1].is_a?(Array)
196
+ # We are dealing with formal[i] and formal[i+1] here, where
197
+ # the first has the size and the second has the contents
198
+ return_values << dereference_pointer_array(formal[i+1], spec[1][0], dereference_pointer(formal[i], T_UINT32))
199
+
200
+ # Increment once more to skip the size param
201
+ i += 1
202
+ else
203
+ return_values << dereference_pointer(formal[i], spec[1])
204
+ end
205
+ end
206
+
207
+ i += 1
208
+ end
209
+
210
+ if return_values.empty?
211
+ nil
212
+ elsif return_values.length == 1
213
+ return_values.first
214
+ else
215
+ return_values
216
+ end
217
+ end
218
+
219
+ # Dereferences a pointer with a given type into a proper Ruby object.
220
+ # If the type is a standard primitive of Ruby-FFI, it simply calls the
221
+ # proper `get_*` method on the pointer. Otherwise, it calls a
222
+ # `read_*` on the Util class.
223
+ #
224
+ # @param [FFI::MemoryPointer] pointer
225
+ # @param [Symbol] type The type of the pointer
226
+ # @return [Object] The value of the dereferenced pointer
227
+ def dereference_pointer(pointer, type)
228
+ c_type, inferred_type = infer_type(type)
229
+
230
+ if pointer.respond_to?("get_#{inferred_type}".to_sym)
231
+ # This handles reading the typical times such as :uint, :int, etc.
232
+ result = pointer.send("get_#{inferred_type}".to_sym, 0)
233
+ result = !(result == 0) if type == T_BOOL
234
+ result
235
+ else
236
+ send("read_#{inferred_type}".to_sym, pointer, type)
237
+ end
238
+ end
239
+
240
+ # Dereferences an array out of a pointer into an array of proper Ruby
241
+ # objects.
242
+ #
243
+ # @param [FFI::MemoryPointer] pointer
244
+ # @param [Symbol] type The type of the pointer
245
+ # @param [Fixnum] length The length of the array
246
+ # @return [Array<Object>]
247
+ def dereference_pointer_array(pointer, type, length)
248
+ # If there are no items in the pointer, just return an empty array
249
+ return [] if length == 0
250
+
251
+ c_type, inferred_type = infer_type(type)
252
+
253
+ array_pointer = pointer.get_pointer(0)
254
+ if array_pointer.respond_to?("get_array_of_#{inferred_type}".to_sym)
255
+ # This handles reading the typical times such as :uint, :int, etc.
256
+ array_pointer.send("get_array_of_#{inferred_type}".to_sym, 0, length)
257
+ else
258
+ send("read_array_of_#{inferred_type}".to_sym, array_pointer, type, length)
259
+ end
260
+ end
261
+
262
+ # Converts a symbol type into a MemoryPointer and yield a block
263
+ # with the pointer, the C type, and the FFI type
264
+ def pointer_for_type(type)
265
+ c_type, type = infer_type(type)
266
+
267
+ # Create the pointer, yield, returning the result of the block
268
+ # if a block is given, or otherwise just returning the pointer
269
+ # and inferred type
270
+ pointer = ::FFI::MemoryPointer.new(c_type)
271
+ if block_given?
272
+ yield pointer, type
273
+ else
274
+ pointer
275
+ end
276
+ end
277
+
278
+ # Converts a ruby string to a UTF16 string
279
+ #
280
+ # @param [String] Ruby String object
281
+ # @return [::FFI::Pointer]
282
+ def string_to_utf16(string)
283
+ return nil if string.nil?
284
+
285
+ ptr = pointer_for_type(:pointer)
286
+ lib.xpcom[:pfnUtf8ToUtf16].call(string, ptr)
287
+ ptr.read_pointer()
288
+ end
289
+
290
+ # Converts a UTF16 string to UTF8
291
+ def utf16_to_string(pointer)
292
+ result_pointer = pointer_for_type(:pointer)
293
+ lib.xpcom[:pfnUtf16ToUtf8].call(pointer, result_pointer)
294
+ lib.xpcom[:pfnUtf16Free].call(pointer)
295
+ result_pointer.read_pointer().read_string().to_s
296
+ end
297
+
298
+ # Reads a unicode string value from a pointer to that value.
299
+ #
300
+ # @return [String]
301
+ def read_unicode_string(ptr, original_type=nil)
302
+ address = ptr.get_pointer(0)
303
+ return "" if address.null?
304
+ utf16_to_string(address)
305
+ end
306
+
307
+ # Reads an interface from the pointer
308
+ #
309
+ # @return [::FFI::Struct]
310
+ def read_interface(ptr, original_type)
311
+ ptr = ptr.get_pointer(0)
312
+ return nil if ptr.null?
313
+
314
+ klass = interface_klass(original_type)
315
+ klass.new(self.class, lib, ptr)
316
+ end
317
+
318
+ # Reads an enum
319
+ #
320
+ # @return [Symbol]
321
+ def read_enum(ptr, original_type)
322
+ klass = interface_klass(original_type)
323
+ klass[ptr.get_uint(0)]
324
+ end
325
+
326
+ # Reads an array of enums
327
+ #
328
+ # @return [Array<Symbol>]
329
+ def read_array_of_enum(ptr, type, length)
330
+ klass = interface_klass(type)
331
+ ptr.get_array_of_uint(0, length).collect do |value|
332
+ klass[value]
333
+ end
334
+ end
335
+
336
+ # Reads an array of structs from a pointer
337
+ #
338
+ # @return [Array<::FFI::Struct>]
339
+ def read_array_of_interface(ptr, type, length)
340
+ klass = interface_klass(type)
341
+ ptr.get_array_of_pointer(0, length).collect do |single_pointer|
342
+ klass.new(self.class, lib, single_pointer)
343
+ end
344
+ end
345
+
346
+ # Reads an array of strings from a pointer
347
+ #
348
+ # @return [Array<String>]
349
+ def read_array_of_unicode_string(ptr, type, length)
350
+ ptr.get_array_of_pointer(0, length).collect do |single_pointer|
351
+ if single_pointer.null?
352
+ nil
353
+ else
354
+ utf16_to_string(single_pointer)
355
+ end
356
+ end
357
+ end
358
+ end
359
+ end
360
+ end
361
+ end
@@ -0,0 +1,175 @@
1
+ module VirtualBox
2
+ module COM
3
+ module Implementer
4
+ class MSCOM < Base
5
+ attr_reader :object
6
+
7
+ # Initializes the MSCOM implementer.
8
+ #
9
+ # @param [AbstractInterface] inteface
10
+ # @param [FFI::Pointer] pointer
11
+ def initialize(interface, lib_base, object)
12
+ super(interface, lib_base)
13
+
14
+ @object = object
15
+ end
16
+
17
+ # Reads a property from the interface with the given name.
18
+ def read_property(name, opts)
19
+ # First get the basic value from the COM object
20
+ method = COM::FFI::Util.camelize(name.to_s)
21
+ value = if ruby_version >= 1.9
22
+ @object.send(method)
23
+ else
24
+ @object[method]
25
+ end
26
+
27
+ # Then depending on the value type, we either return as-is or
28
+ # must wrap it up in another interface class
29
+ returnable_value(value, opts[:value_type])
30
+ end
31
+
32
+ # Writes a property from the interface with the given name and
33
+ # value.
34
+ def write_property(name, value, opts)
35
+ # Set the property with a prepared value
36
+ method = COM::FFI::Util.camelize(name.to_s)
37
+ value = spec_to_args([opts[:value_type]], [value]).first
38
+
39
+ if ruby_version >= 1.9
40
+ @object.send("#{method}=", value)
41
+ else
42
+ @object[method] = value
43
+ end
44
+ end
45
+
46
+ # Calls a function from the interface with the given name
47
+ def call_function(name, args, opts)
48
+ # Convert args to proper values to send and send em!
49
+ args = spec_to_args(opts[:spec], args)
50
+ value = @object.send(COM::FFI::Util.camelize(name.to_s), *args)
51
+
52
+ # TODO: Multiple return values
53
+ returnable_value(value, opts[:value_type])
54
+ end
55
+
56
+ #############################################################
57
+ # Internal Methods, a.k.a. unless you're hacking on the code of this
58
+ # library, you should do well to leave these alone =]
59
+ #############################################################
60
+
61
+ # Takes a function spec and an argument list. This handles properly converting
62
+ # enums to ints and {AbstractInterface}s to proper MSCOM interfaces.
63
+ def spec_to_args(spec, args)
64
+ args = args.dup
65
+
66
+ # First remove all :out parameters from the spec, since those are of no
67
+ # concern for MSCOM at this point
68
+ spec = spec.collect do |item|
69
+ if item.is_a?(Array) && item[0] == :out
70
+ nil
71
+ else
72
+ item
73
+ end
74
+ end.compact
75
+
76
+ spec = spec.collect do |item|
77
+ if item == T_BOOL
78
+ args.shift ? 1 : 0
79
+ elsif item.to_s[0,1] == item.to_s[0,1].upcase
80
+ # Try to get the class from the interfaces
81
+ interface = interface_klass(item.to_sym)
82
+
83
+ if interface.superclass == COM::AbstractInterface
84
+ # For interfaces, get the instance, then dig deep to get the pointer
85
+ # to the VtblParent, which is what the API expects
86
+ instance = args.shift
87
+
88
+ if !instance.nil?
89
+ # Get the actual MSCOM object, rather than the AbstractInterface
90
+ instance.implementer.object
91
+ else
92
+ # If the argument was nil, just pass a nil pointer as the argument
93
+ nil
94
+ end
95
+ elsif interface.superclass == COM::AbstractEnum
96
+ # For enums, we need the value of the enum
97
+ interface.index(args.shift.to_sym)
98
+ end
99
+ else
100
+ # Simply replace spec item with next item in args
101
+ # list
102
+ args.shift
103
+ end
104
+ end
105
+ end
106
+
107
+ # Takes a value (returned from a WIN32OLE object) and a type and converts
108
+ # to a proper ruby return value type.
109
+ def returnable_value(value, type)
110
+ # Types which are void or nil just return
111
+ return nil if type.nil? || type == :void
112
+
113
+ klass = type.is_a?(Array) ? type.first : type
114
+ ignore, inferred_type = infer_type(klass)
115
+
116
+ array_of = type.is_a?(Array) ? "array_of_" : ""
117
+ send("read_#{array_of}#{inferred_type}", value, type)
118
+ end
119
+
120
+ def read_unicode_string(value, type)
121
+ # Return as-is
122
+ value
123
+ end
124
+
125
+ def read_char(value, type)
126
+ # Convert to a boolean
127
+ !(value.to_s == "0")
128
+ end
129
+
130
+ def read_ushort(value, type)
131
+ value.to_i
132
+ end
133
+
134
+ def read_uint(value, type)
135
+ value.to_i
136
+ end
137
+
138
+ def read_ulong(value, type)
139
+ value.to_i
140
+ end
141
+
142
+ def read_int(value, type)
143
+ value.to_i
144
+ end
145
+
146
+ def read_long(value, type)
147
+ value.to_i
148
+ end
149
+
150
+ def read_enum(value, type)
151
+ interface_klass(type)[value]
152
+ end
153
+
154
+ def read_interface(value, type)
155
+ return nil if value.nil?
156
+ interface_klass(type).new(self.class, lib, value)
157
+ end
158
+
159
+ def read_array_of_unicode_string(value, type)
160
+ # Return as-is, since MSCOM returns ruby strings!
161
+ value
162
+ end
163
+
164
+ def read_array_of_interface(value, type)
165
+ klass = interface_klass(type.first)
166
+ value.collect do |item|
167
+ if !item.nil?
168
+ klass.new(self.class, lib, item)
169
+ end
170
+ end
171
+ end
172
+ end
173
+ end
174
+ end
175
+ end