openc3 5.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (307) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +18 -0
  3. data/Guardfile +35 -0
  4. data/LICENSE.txt +727 -0
  5. data/README.md +37 -0
  6. data/Rakefile +131 -0
  7. data/bin/cstol_converter +1178 -0
  8. data/bin/openc3cli +531 -0
  9. data/bin/rubysloc +139 -0
  10. data/data/config/_array_params.yaml +23 -0
  11. data/data/config/_id_items.yaml +24 -0
  12. data/data/config/_id_params.yaml +58 -0
  13. data/data/config/_interfaces.yaml +214 -0
  14. data/data/config/_interfaces.yaml.err +1017 -0
  15. data/data/config/_items.yaml +20 -0
  16. data/data/config/_params.yaml +60 -0
  17. data/data/config/cmd_tlm_server.yaml +136 -0
  18. data/data/config/command.yaml +44 -0
  19. data/data/config/command_modifiers.yaml +160 -0
  20. data/data/config/command_telemetry.yaml +3 -0
  21. data/data/config/interface_modifiers.yaml +104 -0
  22. data/data/config/item_modifiers.yaml +221 -0
  23. data/data/config/microservice.yaml +78 -0
  24. data/data/config/param_item_modifiers.yaml +52 -0
  25. data/data/config/parameter_modifiers.yaml +200 -0
  26. data/data/config/plugins.yaml +80 -0
  27. data/data/config/protocols.yaml +290 -0
  28. data/data/config/screen.yaml +147 -0
  29. data/data/config/table_manager.yaml +89 -0
  30. data/data/config/table_parameter_modifiers.yaml +9 -0
  31. data/data/config/target.yaml +142 -0
  32. data/data/config/target_config.yaml +94 -0
  33. data/data/config/telemetry.yaml +87 -0
  34. data/data/config/telemetry_modifiers.yaml +159 -0
  35. data/data/config/tool.yaml +63 -0
  36. data/data/config/unknown.yaml +3 -0
  37. data/data/config/widgets.yaml +1505 -0
  38. data/ext/mkrf_conf.rb +49 -0
  39. data/ext/openc3/ext/array/array.c +122 -0
  40. data/ext/openc3/ext/array/extconf.rb +13 -0
  41. data/ext/openc3/ext/buffered_file/buffered_file.c +198 -0
  42. data/ext/openc3/ext/buffered_file/extconf.rb +13 -0
  43. data/ext/openc3/ext/config_parser/config_parser.c +280 -0
  44. data/ext/openc3/ext/config_parser/extconf.rb +13 -0
  45. data/ext/openc3/ext/crc/crc.c +351 -0
  46. data/ext/openc3/ext/crc/extconf.rb +13 -0
  47. data/ext/openc3/ext/openc3_io/extconf.rb +13 -0
  48. data/ext/openc3/ext/openc3_io/openc3_io.c +158 -0
  49. data/ext/openc3/ext/packet/extconf.rb +13 -0
  50. data/ext/openc3/ext/packet/packet.c +318 -0
  51. data/ext/openc3/ext/platform/extconf.rb +13 -0
  52. data/ext/openc3/ext/platform/platform.c +134 -0
  53. data/ext/openc3/ext/polynomial_conversion/extconf.rb +13 -0
  54. data/ext/openc3/ext/polynomial_conversion/polynomial_conversion.c +79 -0
  55. data/ext/openc3/ext/string/extconf.rb +13 -0
  56. data/ext/openc3/ext/string/string.c +63 -0
  57. data/ext/openc3/ext/structure/structure.c +1719 -0
  58. data/ext/openc3/ext/tabbed_plots_config/extconf.rb +13 -0
  59. data/ext/openc3/ext/tabbed_plots_config/tabbed_plots_config.c +62 -0
  60. data/ext/openc3/ext/telemetry/extconf.rb +13 -0
  61. data/ext/openc3/ext/telemetry/telemetry.c +336 -0
  62. data/lib/cosmos.rb +20 -0
  63. data/lib/cosmosc2.rb +20 -0
  64. data/lib/openc3/api/api.rb +39 -0
  65. data/lib/openc3/api/authorized_api.rb +30 -0
  66. data/lib/openc3/api/cmd_api.rb +451 -0
  67. data/lib/openc3/api/config_api.rb +58 -0
  68. data/lib/openc3/api/interface_api.rb +117 -0
  69. data/lib/openc3/api/limits_api.rb +375 -0
  70. data/lib/openc3/api/router_api.rb +117 -0
  71. data/lib/openc3/api/settings_api.rb +70 -0
  72. data/lib/openc3/api/target_api.rb +78 -0
  73. data/lib/openc3/api/tlm_api.rb +455 -0
  74. data/lib/openc3/bridge/bridge.rb +54 -0
  75. data/lib/openc3/bridge/bridge_config.rb +167 -0
  76. data/lib/openc3/bridge/bridge_interface_thread.rb +42 -0
  77. data/lib/openc3/bridge/bridge_router_thread.rb +42 -0
  78. data/lib/openc3/ccsds/ccsds_packet.rb +68 -0
  79. data/lib/openc3/ccsds/ccsds_parser.rb +148 -0
  80. data/lib/openc3/config/config_parser.rb +549 -0
  81. data/lib/openc3/config/meta_config_parser.rb +74 -0
  82. data/lib/openc3/conversions/conversion.rb +70 -0
  83. data/lib/openc3/conversions/generic_conversion.rb +83 -0
  84. data/lib/openc3/conversions/packet_time_formatted_conversion.rb +43 -0
  85. data/lib/openc3/conversions/packet_time_seconds_conversion.rb +43 -0
  86. data/lib/openc3/conversions/polynomial_conversion.rb +87 -0
  87. data/lib/openc3/conversions/processor_conversion.rb +70 -0
  88. data/lib/openc3/conversions/received_count_conversion.rb +38 -0
  89. data/lib/openc3/conversions/received_time_formatted_conversion.rb +42 -0
  90. data/lib/openc3/conversions/received_time_seconds_conversion.rb +42 -0
  91. data/lib/openc3/conversions/segmented_polynomial_conversion.rb +171 -0
  92. data/lib/openc3/conversions/unix_time_conversion.rb +68 -0
  93. data/lib/openc3/conversions/unix_time_formatted_conversion.rb +49 -0
  94. data/lib/openc3/conversions/unix_time_seconds_conversion.rb +49 -0
  95. data/lib/openc3/conversions.rb +34 -0
  96. data/lib/openc3/core_ext/array.rb +416 -0
  97. data/lib/openc3/core_ext/binding.rb +29 -0
  98. data/lib/openc3/core_ext/class.rb +72 -0
  99. data/lib/openc3/core_ext/exception.rb +61 -0
  100. data/lib/openc3/core_ext/file.rb +83 -0
  101. data/lib/openc3/core_ext/hash.rb +37 -0
  102. data/lib/openc3/core_ext/io.rb +134 -0
  103. data/lib/openc3/core_ext/kernel.rb +42 -0
  104. data/lib/openc3/core_ext/math.rb +128 -0
  105. data/lib/openc3/core_ext/matrix.rb +156 -0
  106. data/lib/openc3/core_ext/objectspace.rb +36 -0
  107. data/lib/openc3/core_ext/openc3_io.rb +57 -0
  108. data/lib/openc3/core_ext/range.rb +27 -0
  109. data/lib/openc3/core_ext/socket.rb +38 -0
  110. data/lib/openc3/core_ext/string.rb +389 -0
  111. data/lib/openc3/core_ext/stringio.rb +33 -0
  112. data/lib/openc3/core_ext/time.rb +508 -0
  113. data/lib/openc3/core_ext.rb +36 -0
  114. data/lib/openc3/interfaces/interface.rb +498 -0
  115. data/lib/openc3/interfaces/linc_interface.rb +475 -0
  116. data/lib/openc3/interfaces/protocols/burst_protocol.rb +192 -0
  117. data/lib/openc3/interfaces/protocols/crc_protocol.rb +193 -0
  118. data/lib/openc3/interfaces/protocols/fixed_protocol.rb +155 -0
  119. data/lib/openc3/interfaces/protocols/ignore_packet_protocol.rb +56 -0
  120. data/lib/openc3/interfaces/protocols/length_protocol.rb +165 -0
  121. data/lib/openc3/interfaces/protocols/override_protocol.rb +60 -0
  122. data/lib/openc3/interfaces/protocols/preidentified_protocol.rb +206 -0
  123. data/lib/openc3/interfaces/protocols/protocol.rb +82 -0
  124. data/lib/openc3/interfaces/protocols/template_protocol.rb +261 -0
  125. data/lib/openc3/interfaces/protocols/terminated_protocol.rb +93 -0
  126. data/lib/openc3/interfaces/serial_interface.rb +94 -0
  127. data/lib/openc3/interfaces/simulated_target_interface.rb +168 -0
  128. data/lib/openc3/interfaces/stream_interface.rb +81 -0
  129. data/lib/openc3/interfaces/tcpip_client_interface.rb +69 -0
  130. data/lib/openc3/interfaces/tcpip_server_interface.rb +629 -0
  131. data/lib/openc3/interfaces/udp_interface.rb +169 -0
  132. data/lib/openc3/interfaces.rb +44 -0
  133. data/lib/openc3/io/buffered_file.rb +109 -0
  134. data/lib/openc3/io/io_multiplexer.rb +80 -0
  135. data/lib/openc3/io/json_api_object.rb +208 -0
  136. data/lib/openc3/io/json_drb.rb +335 -0
  137. data/lib/openc3/io/json_drb_object.rb +114 -0
  138. data/lib/openc3/io/json_drb_rack.rb +84 -0
  139. data/lib/openc3/io/json_rpc.rb +420 -0
  140. data/lib/openc3/io/openc3_snmp.rb +58 -0
  141. data/lib/openc3/io/posix_serial_driver.rb +156 -0
  142. data/lib/openc3/io/raw_logger.rb +167 -0
  143. data/lib/openc3/io/raw_logger_pair.rb +77 -0
  144. data/lib/openc3/io/serial_driver.rb +105 -0
  145. data/lib/openc3/io/stderr.rb +43 -0
  146. data/lib/openc3/io/stdout.rb +43 -0
  147. data/lib/openc3/io/udp_sockets.rb +194 -0
  148. data/lib/openc3/io/win32_serial_driver.rb +196 -0
  149. data/lib/openc3/logs/log_writer.rb +302 -0
  150. data/lib/openc3/logs/packet_log_constants.rb +62 -0
  151. data/lib/openc3/logs/packet_log_reader.rb +345 -0
  152. data/lib/openc3/logs/packet_log_writer.rb +299 -0
  153. data/lib/openc3/logs/text_log_writer.rb +68 -0
  154. data/lib/openc3/logs.rb +25 -0
  155. data/lib/openc3/microservices/cleanup_microservice.rb +68 -0
  156. data/lib/openc3/microservices/decom_microservice.rb +136 -0
  157. data/lib/openc3/microservices/interface_microservice.rb +532 -0
  158. data/lib/openc3/microservices/log_microservice.rb +108 -0
  159. data/lib/openc3/microservices/microservice.rb +204 -0
  160. data/lib/openc3/microservices/plugin_microservice.rb +43 -0
  161. data/lib/openc3/microservices/reaction_microservice.rb +541 -0
  162. data/lib/openc3/microservices/reducer_microservice.rb +313 -0
  163. data/lib/openc3/microservices/router_microservice.rb +44 -0
  164. data/lib/openc3/microservices/text_log_microservice.rb +84 -0
  165. data/lib/openc3/microservices/timeline_microservice.rb +363 -0
  166. data/lib/openc3/microservices/trigger_group_microservice.rb +638 -0
  167. data/lib/openc3/models/activity_model.rb +319 -0
  168. data/lib/openc3/models/auth_model.rb +65 -0
  169. data/lib/openc3/models/cvt_model.rb +185 -0
  170. data/lib/openc3/models/environment_model.rb +58 -0
  171. data/lib/openc3/models/gem_model.rb +137 -0
  172. data/lib/openc3/models/info_model.rb +31 -0
  173. data/lib/openc3/models/interface_model.rb +281 -0
  174. data/lib/openc3/models/interface_status_model.rb +117 -0
  175. data/lib/openc3/models/metadata_model.rb +139 -0
  176. data/lib/openc3/models/metric_model.rb +59 -0
  177. data/lib/openc3/models/microservice_model.rb +206 -0
  178. data/lib/openc3/models/microservice_status_model.rb +74 -0
  179. data/lib/openc3/models/model.rb +204 -0
  180. data/lib/openc3/models/note_model.rb +122 -0
  181. data/lib/openc3/models/notification_model.rb +40 -0
  182. data/lib/openc3/models/ping_model.rb +35 -0
  183. data/lib/openc3/models/plugin_model.rb +292 -0
  184. data/lib/openc3/models/process_status_model.rb +76 -0
  185. data/lib/openc3/models/reaction_model.rb +322 -0
  186. data/lib/openc3/models/reducer_model.rb +65 -0
  187. data/lib/openc3/models/router_model.rb +35 -0
  188. data/lib/openc3/models/router_status_model.rb +27 -0
  189. data/lib/openc3/models/scope_model.rb +153 -0
  190. data/lib/openc3/models/settings_model.rb +55 -0
  191. data/lib/openc3/models/sorted_model.rb +167 -0
  192. data/lib/openc3/models/target_model.rb +759 -0
  193. data/lib/openc3/models/timeline_model.rb +154 -0
  194. data/lib/openc3/models/tool_config_model.rb +38 -0
  195. data/lib/openc3/models/tool_model.rb +262 -0
  196. data/lib/openc3/models/trigger_group_model.rb +186 -0
  197. data/lib/openc3/models/trigger_model.rb +330 -0
  198. data/lib/openc3/models/widget_model.rb +138 -0
  199. data/lib/openc3/operators/microservice_operator.rb +128 -0
  200. data/lib/openc3/operators/operator.rb +277 -0
  201. data/lib/openc3/packets/binary_accessor.rb +1207 -0
  202. data/lib/openc3/packets/commands.rb +373 -0
  203. data/lib/openc3/packets/json_packet.rb +134 -0
  204. data/lib/openc3/packets/limits.rb +271 -0
  205. data/lib/openc3/packets/limits_response.rb +53 -0
  206. data/lib/openc3/packets/packet.rb +1168 -0
  207. data/lib/openc3/packets/packet_config.rb +625 -0
  208. data/lib/openc3/packets/packet_item.rb +586 -0
  209. data/lib/openc3/packets/packet_item_limits.rb +162 -0
  210. data/lib/openc3/packets/parsers/format_string_parser.rb +65 -0
  211. data/lib/openc3/packets/parsers/limits_parser.rb +159 -0
  212. data/lib/openc3/packets/parsers/limits_response_parser.rb +61 -0
  213. data/lib/openc3/packets/parsers/packet_item_parser.rb +272 -0
  214. data/lib/openc3/packets/parsers/packet_parser.rb +134 -0
  215. data/lib/openc3/packets/parsers/processor_parser.rb +73 -0
  216. data/lib/openc3/packets/parsers/state_parser.rb +127 -0
  217. data/lib/openc3/packets/parsers/xtce_converter.rb +442 -0
  218. data/lib/openc3/packets/parsers/xtce_parser.rb +722 -0
  219. data/lib/openc3/packets/structure.rb +553 -0
  220. data/lib/openc3/packets/structure_item.rb +365 -0
  221. data/lib/openc3/packets/telemetry.rb +487 -0
  222. data/lib/openc3/processors/processor.rb +86 -0
  223. data/lib/openc3/processors/statistics_processor.rb +82 -0
  224. data/lib/openc3/processors/watermark_processor.rb +58 -0
  225. data/lib/openc3/processors.rb +24 -0
  226. data/lib/openc3/script/api_shared.rb +828 -0
  227. data/lib/openc3/script/calendar.rb +89 -0
  228. data/lib/openc3/script/commands.rb +227 -0
  229. data/lib/openc3/script/exceptions.rb +29 -0
  230. data/lib/openc3/script/extract.rb +161 -0
  231. data/lib/openc3/script/limits.rb +60 -0
  232. data/lib/openc3/script/script.rb +299 -0
  233. data/lib/openc3/script/script_runner.rb +238 -0
  234. data/lib/openc3/script/storage.rb +146 -0
  235. data/lib/openc3/script/suite.rb +542 -0
  236. data/lib/openc3/script/suite_results.rb +196 -0
  237. data/lib/openc3/script/suite_runner.rb +217 -0
  238. data/lib/openc3/script.rb +21 -0
  239. data/lib/openc3/streams/serial_stream.rb +167 -0
  240. data/lib/openc3/streams/stream.rb +63 -0
  241. data/lib/openc3/streams/tcpip_client_stream.rb +116 -0
  242. data/lib/openc3/streams/tcpip_socket_stream.rb +195 -0
  243. data/lib/openc3/system/system.rb +127 -0
  244. data/lib/openc3/system/system_config.rb +411 -0
  245. data/lib/openc3/system/target.rb +269 -0
  246. data/lib/openc3/system.rb +24 -0
  247. data/lib/openc3/tools/cmd_tlm_server/api.rb +20 -0
  248. data/lib/openc3/tools/cmd_tlm_server/cmd_tlm_server_config.rb +320 -0
  249. data/lib/openc3/tools/cmd_tlm_server/interface_thread.rb +294 -0
  250. data/lib/openc3/tools/table_manager/table.rb +77 -0
  251. data/lib/openc3/tools/table_manager/table_config.rb +273 -0
  252. data/lib/openc3/tools/table_manager/table_item.rb +90 -0
  253. data/lib/openc3/tools/table_manager/table_item_parser.rb +66 -0
  254. data/lib/openc3/tools/table_manager/table_manager_core.rb +333 -0
  255. data/lib/openc3/tools/table_manager/table_parser.rb +93 -0
  256. data/lib/openc3/tools/test_runner/test.rb +67 -0
  257. data/lib/openc3/top_level.rb +595 -0
  258. data/lib/openc3/topics/autonomic_topic.rb +52 -0
  259. data/lib/openc3/topics/calendar_topic.rb +44 -0
  260. data/lib/openc3/topics/command_decom_topic.rb +76 -0
  261. data/lib/openc3/topics/command_topic.rb +83 -0
  262. data/lib/openc3/topics/config_topic.rb +68 -0
  263. data/lib/openc3/topics/interface_topic.rb +73 -0
  264. data/lib/openc3/topics/limits_event_topic.rb +109 -0
  265. data/lib/openc3/topics/notifications_topic.rb +28 -0
  266. data/lib/openc3/topics/router_topic.rb +85 -0
  267. data/lib/openc3/topics/telemetry_decom_topic.rb +54 -0
  268. data/lib/openc3/topics/telemetry_topic.rb +36 -0
  269. data/lib/openc3/topics/timeline_topic.rb +45 -0
  270. data/lib/openc3/topics/topic.rb +53 -0
  271. data/lib/openc3/utilities/authentication.rb +141 -0
  272. data/lib/openc3/utilities/authorization.rb +51 -0
  273. data/lib/openc3/utilities/crc.rb +278 -0
  274. data/lib/openc3/utilities/csv.rb +153 -0
  275. data/lib/openc3/utilities/logger.rb +187 -0
  276. data/lib/openc3/utilities/message_log.rb +91 -0
  277. data/lib/openc3/utilities/metric.rb +141 -0
  278. data/lib/openc3/utilities/process_manager.rb +139 -0
  279. data/lib/openc3/utilities/quaternion.rb +257 -0
  280. data/lib/openc3/utilities/ruby_lex_utils.rb +568 -0
  281. data/lib/openc3/utilities/s3.rb +202 -0
  282. data/lib/openc3/utilities/s3_autoload.rb +9 -0
  283. data/lib/openc3/utilities/s3_file_cache.rb +274 -0
  284. data/lib/openc3/utilities/simulated_target.rb +117 -0
  285. data/lib/openc3/utilities/sleeper.rb +51 -0
  286. data/lib/openc3/utilities/store.rb +23 -0
  287. data/lib/openc3/utilities/store_autoload.rb +237 -0
  288. data/lib/openc3/utilities/zip.rb +21 -0
  289. data/lib/openc3/utilities.rb +35 -0
  290. data/lib/openc3/version.rb +14 -0
  291. data/lib/openc3/win32/excel.rb +132 -0
  292. data/lib/openc3/win32/win32.rb +402 -0
  293. data/lib/openc3/win32/win32_main.rb +333 -0
  294. data/lib/openc3.rb +49 -0
  295. data/tasks/gemfile_stats.rake +113 -0
  296. data/tasks/spec.rake +30 -0
  297. data/templates/plugin-template/README.md +15 -0
  298. data/templates/plugin-template/Rakefile +12 -0
  299. data/templates/plugin-template/plugin.gemspec +23 -0
  300. data/templates/plugin-template/plugin.txt +9 -0
  301. data/templates/plugin-template/targets/TARGET/cmd_tlm/cmd.txt +8 -0
  302. data/templates/plugin-template/targets/TARGET/cmd_tlm/tlm.txt +8 -0
  303. data/templates/plugin-template/targets/TARGET/lib/target.rb +10 -0
  304. data/templates/plugin-template/targets/TARGET/procedures/procedure.rb +3 -0
  305. data/templates/plugin-template/targets/TARGET/screens/status.txt +9 -0
  306. data/templates/plugin-template/targets/TARGET/target.txt +5 -0
  307. metadata +849 -0
@@ -0,0 +1,1719 @@
1
+ /*
2
+ # Copyright 2022 Ball Aerospace & Technologies Corp.
3
+ # All Rights Reserved.
4
+ #
5
+ # This program is free software; you can modify and/or redistribute it
6
+ # under the terms of the GNU Affero General Public License
7
+ # as published by the Free Software Foundation; version 3 with
8
+ # attribution addendums as found in the LICENSE.txt
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Affero General Public License for more details.
14
+ */
15
+
16
+ /*
17
+ # Modified by OpenC3, Inc.
18
+ # All changes Copyright 2022, OpenC3, Inc.
19
+ # All Rights Reserved
20
+ */
21
+
22
+ #include "ruby.h"
23
+ #include "stdio.h"
24
+
25
+ #define TO_BIGNUM(x) (FIXNUM_P(x) ? rb_int2big(FIX2LONG(x)) : x)
26
+ #define BYTE_ALIGNED(x) (((x) % 8) == 0)
27
+
28
+ static const int endianness_check = 1;
29
+ static VALUE HOST_ENDIANNESS = Qnil;
30
+ static VALUE ZERO_STRING = Qnil;
31
+ static VALUE ASCII_8BIT_STRING = Qnil;
32
+
33
+ static VALUE MIN_INT8 = Qnil;
34
+ static VALUE MAX_INT8 = Qnil;
35
+ static VALUE MAX_UINT8 = Qnil;
36
+ static VALUE MIN_INT16 = Qnil;
37
+ static VALUE MAX_INT16 = Qnil;
38
+ static VALUE MAX_UINT16 = Qnil;
39
+ static VALUE MIN_INT32 = Qnil;
40
+ static VALUE MAX_INT32 = Qnil;
41
+ static VALUE MAX_UINT32 = Qnil;
42
+ static VALUE MIN_INT64 = Qnil;
43
+ static VALUE MAX_INT64 = Qnil;
44
+ static VALUE MAX_UINT64 = Qnil;
45
+
46
+ static VALUE mOpenC3 = Qnil;
47
+ static VALUE cBinaryAccessor = Qnil;
48
+ static VALUE cStructure = Qnil;
49
+ static VALUE cStructureItem = Qnil;
50
+
51
+ static ID id_method_to_s = 0;
52
+ static ID id_method_raise_buffer_error = 0;
53
+ static ID id_method_read_array = 0;
54
+ static ID id_method_force_encoding = 0;
55
+ static ID id_method_freeze = 0;
56
+ static ID id_method_slice = 0;
57
+ static ID id_method_reverse = 0;
58
+ static ID id_method_Integer = 0;
59
+ static ID id_method_Float = 0;
60
+ static ID id_method_kind_of = 0;
61
+ static ID id_method_allocate_buffer_if_needed = 0;
62
+
63
+ static ID id_ivar_buffer = 0;
64
+ static ID id_ivar_bit_offset = 0;
65
+ static ID id_ivar_bit_size = 0;
66
+ static ID id_ivar_array_size = 0;
67
+ static ID id_ivar_endianness = 0;
68
+ static ID id_ivar_data_type = 0;
69
+ static ID id_ivar_default_endianness = 0;
70
+ static ID id_ivar_item_class = 0;
71
+ static ID id_ivar_items = 0;
72
+ static ID id_ivar_sorted_items = 0;
73
+ static ID id_ivar_defined_length = 0;
74
+ static ID id_ivar_defined_length_bits = 0;
75
+ static ID id_ivar_pos_bit_size = 0;
76
+ static ID id_ivar_neg_bit_size = 0;
77
+ static ID id_ivar_fixed_size = 0;
78
+ static ID id_ivar_short_buffer_allowed = 0;
79
+ static ID id_ivar_mutex = 0;
80
+ static ID id_ivar_create_index = 0;
81
+
82
+ static ID id_const_ASCII_8BIT_STRING = 0;
83
+ static ID id_const_ZERO_STRING = 0;
84
+
85
+ static VALUE symbol_LITTLE_ENDIAN = Qnil;
86
+ static VALUE symbol_BIG_ENDIAN = Qnil;
87
+ static VALUE symbol_INT = Qnil;
88
+ static VALUE symbol_UINT = Qnil;
89
+ static VALUE symbol_FLOAT = Qnil;
90
+ static VALUE symbol_STRING = Qnil;
91
+ static VALUE symbol_BLOCK = Qnil;
92
+ static VALUE symbol_DERIVED = Qnil;
93
+ static VALUE symbol_read = Qnil;
94
+ static VALUE symbol_write = Qnil;
95
+ static VALUE symbol_TRUNCATE = Qnil;
96
+ static VALUE symbol_SATURATE = Qnil;
97
+ static VALUE symbol_ERROR = Qnil;
98
+ static VALUE symbol_ERROR_ALLOW_HEX = Qnil;
99
+
100
+ /*
101
+ * Perform an left bit shift on a string
102
+ */
103
+ static void left_shift_byte_array(unsigned char *array, int array_length, int shift)
104
+ {
105
+ int current_index = 0;
106
+ int previous_index = 0;
107
+ unsigned char saved_bits = 0;
108
+ unsigned char saved_bits_mask = (0xFF << (8 - shift));
109
+ unsigned char sign_extension_remove_mask = ~(0xFF << shift);
110
+
111
+ for (current_index = 0; current_index < array_length; current_index++)
112
+ {
113
+ /* Save bits that will be lost */
114
+ saved_bits = ((array[current_index] & saved_bits_mask) >> (8 - shift)) & sign_extension_remove_mask;
115
+
116
+ /* Perform shift on current byte */
117
+ array[current_index] <<= shift;
118
+
119
+ /* Add Saved bits to end of previous byte */
120
+ if (current_index > 0)
121
+ {
122
+ array[previous_index] |= saved_bits;
123
+ }
124
+
125
+ /* Update previous index */
126
+ previous_index = current_index;
127
+ }
128
+ }
129
+
130
+ /*
131
+ * Perform an unsigned right bit shift on a string
132
+ */
133
+ static void unsigned_right_shift_byte_array(unsigned char *array, int array_length, int shift)
134
+ {
135
+ int current_index = 0;
136
+ int previous_index = 0;
137
+ unsigned char saved_bits = 0;
138
+ unsigned char saved_bits_mask = ~(0xFF << shift);
139
+ unsigned char sign_extension_remove_mask = ~(0xFF << (8 - shift));
140
+
141
+ for (current_index = array_length - 1; current_index >= 0; current_index--)
142
+ {
143
+ /* Save bits that will be lost */
144
+ saved_bits = (array[current_index] & saved_bits_mask) << (8 - shift);
145
+
146
+ /* Perform shift on current byte */
147
+ array[current_index] = (array[current_index] >> shift) & sign_extension_remove_mask;
148
+
149
+ /* Add Saved bits to beginning of previous byte */
150
+ if (current_index != (array_length - 1))
151
+ {
152
+ array[previous_index] |= saved_bits;
153
+ }
154
+
155
+ /* Update previous index */
156
+ previous_index = current_index;
157
+ }
158
+ }
159
+
160
+ /*
161
+ * Perform an signed right bit shift on a string
162
+ */
163
+ static void signed_right_shift_byte_array(unsigned char *array, int array_length, int shift)
164
+ {
165
+ unsigned char start_bits_mask = (0xFF << (8 - shift));
166
+ int is_signed = (0x80 & array[0]);
167
+
168
+ unsigned_right_shift_byte_array(array, array_length, shift);
169
+
170
+ if (is_signed)
171
+ {
172
+ array[0] |= start_bits_mask;
173
+ }
174
+ }
175
+
176
+ /*
177
+ * Perform an unsigned bit shift on a string
178
+ */
179
+ static void unsigned_shift_byte_array(unsigned char *array, int array_length, int shift)
180
+ {
181
+ if (shift < 0)
182
+ {
183
+ left_shift_byte_array(array, array_length, -shift);
184
+ }
185
+ else if (shift > 0)
186
+ {
187
+ unsigned_right_shift_byte_array(array, array_length, shift);
188
+ }
189
+ }
190
+
191
+ /*
192
+ * Reverse the byte order in a string.
193
+ */
194
+ static void reverse_bytes(unsigned char *array, int array_length)
195
+ {
196
+ int first_index = 0;
197
+ int second_index = 0;
198
+ unsigned char temp_byte = 0;
199
+
200
+ for (first_index = 0; first_index < (array_length / 2); first_index++)
201
+ {
202
+ second_index = array_length - 1 - first_index;
203
+ temp_byte = array[first_index];
204
+ array[first_index] = array[second_index];
205
+ array[second_index] = temp_byte;
206
+ }
207
+ }
208
+
209
+ static void read_aligned_16(int lower_bound, int upper_bound, VALUE endianness, unsigned char *buffer, unsigned char *read_value)
210
+ {
211
+ if (endianness == HOST_ENDIANNESS)
212
+ {
213
+ read_value[1] = buffer[upper_bound];
214
+ read_value[0] = buffer[lower_bound];
215
+ }
216
+ else
217
+ {
218
+ read_value[0] = buffer[upper_bound];
219
+ read_value[1] = buffer[lower_bound];
220
+ }
221
+ }
222
+
223
+ static void read_aligned_32(int lower_bound, int upper_bound, VALUE endianness, unsigned char *buffer, unsigned char *read_value)
224
+ {
225
+ if (endianness == HOST_ENDIANNESS)
226
+ {
227
+ read_value[3] = buffer[upper_bound];
228
+ read_value[2] = buffer[upper_bound - 1];
229
+ read_value[1] = buffer[lower_bound + 1];
230
+ read_value[0] = buffer[lower_bound];
231
+ }
232
+ else
233
+ {
234
+ read_value[0] = buffer[upper_bound];
235
+ read_value[1] = buffer[upper_bound - 1];
236
+ read_value[2] = buffer[lower_bound + 1];
237
+ read_value[3] = buffer[lower_bound];
238
+ }
239
+ }
240
+
241
+ static void read_aligned_64(int lower_bound, int upper_bound, VALUE endianness, unsigned char *buffer, unsigned char *read_value)
242
+ {
243
+ if (endianness == HOST_ENDIANNESS)
244
+ {
245
+ read_value[7] = buffer[upper_bound];
246
+ read_value[6] = buffer[upper_bound - 1];
247
+ read_value[5] = buffer[upper_bound - 2];
248
+ read_value[4] = buffer[upper_bound - 3];
249
+ read_value[3] = buffer[lower_bound + 3];
250
+ read_value[2] = buffer[lower_bound + 2];
251
+ read_value[1] = buffer[lower_bound + 1];
252
+ read_value[0] = buffer[lower_bound];
253
+ }
254
+ else
255
+ {
256
+ read_value[0] = buffer[upper_bound];
257
+ read_value[1] = buffer[upper_bound - 1];
258
+ read_value[2] = buffer[upper_bound - 2];
259
+ read_value[3] = buffer[upper_bound - 3];
260
+ read_value[4] = buffer[lower_bound + 3];
261
+ read_value[5] = buffer[lower_bound + 2];
262
+ read_value[6] = buffer[lower_bound + 1];
263
+ read_value[7] = buffer[lower_bound];
264
+ }
265
+ }
266
+
267
+ static void read_bitfield(int lower_bound, int upper_bound, int bit_offset, int bit_size, int given_bit_offset, int given_bit_size, VALUE endianness, unsigned char *buffer, int buffer_length, unsigned char *read_value)
268
+ {
269
+ /* Local variables */
270
+ int num_bytes = 0;
271
+ int total_bits = 0;
272
+ int start_bits = 0;
273
+ int end_bits = 0;
274
+ int temp_upper = 0;
275
+ unsigned char end_mask = 0;
276
+
277
+ /* Copy Data For Bitfield into read_value */
278
+ if (endianness == symbol_LITTLE_ENDIAN)
279
+ {
280
+ /* Bitoffset always refers to the most significant bit of a bitfield */
281
+ num_bytes = (((bit_offset % 8) + bit_size - 1) / 8) + 1;
282
+ upper_bound = bit_offset / 8;
283
+ lower_bound = upper_bound - num_bytes + 1;
284
+
285
+ if (lower_bound < 0)
286
+ {
287
+ rb_raise(rb_eArgError, "LITTLE_ENDIAN bitfield with bit_offset %d and bit_size %d is invalid", given_bit_offset, given_bit_size);
288
+ }
289
+
290
+ memcpy(read_value, &buffer[lower_bound], num_bytes);
291
+ reverse_bytes(read_value, num_bytes);
292
+ }
293
+ else
294
+ {
295
+ num_bytes = upper_bound - lower_bound + 1;
296
+ memcpy(read_value, &buffer[lower_bound], num_bytes);
297
+ }
298
+
299
+ /* Determine temp upper bound */
300
+ temp_upper = upper_bound - lower_bound;
301
+
302
+ /* Handle Bitfield */
303
+ total_bits = (temp_upper + 1) * 8;
304
+ start_bits = bit_offset % 8;
305
+ end_bits = total_bits - start_bits - bit_size;
306
+ end_mask = 0xFF << end_bits;
307
+
308
+ /* Mask off unwanted bits at end */
309
+ read_value[temp_upper] &= end_mask;
310
+
311
+ /* Shift off unwanted bits at beginning */
312
+ unsigned_shift_byte_array(read_value, num_bytes, -start_bits);
313
+ }
314
+
315
+ static void write_bitfield(int lower_bound, int upper_bound, int bit_offset, int bit_size, int given_bit_offset, int given_bit_size, VALUE endianness, unsigned char *buffer, int buffer_length, unsigned char *write_value)
316
+ {
317
+ /* Local variables */
318
+ int num_bytes = 0;
319
+ int total_bits = 0;
320
+ int start_bits = 0;
321
+ int end_bits = 0;
322
+ int temp_upper = 0;
323
+ unsigned char start_mask = 0;
324
+ unsigned char end_mask = 0;
325
+
326
+ if (endianness == symbol_LITTLE_ENDIAN)
327
+ {
328
+ /* Bitoffset always refers to the most significant bit of a bitfield */
329
+ num_bytes = (((bit_offset % 8) + bit_size - 1) / 8) + 1;
330
+ upper_bound = bit_offset / 8;
331
+ lower_bound = upper_bound - num_bytes + 1;
332
+
333
+ if (lower_bound < 0)
334
+ {
335
+ rb_raise(rb_eArgError, "LITTLE_ENDIAN bitfield with bit_offset %d and bit_size %d is invalid", given_bit_offset, given_bit_size);
336
+ }
337
+ }
338
+ else
339
+ {
340
+ num_bytes = upper_bound - lower_bound + 1;
341
+ }
342
+
343
+ /* Determine temp upper bound */
344
+ temp_upper = upper_bound - lower_bound;
345
+
346
+ /* Handle Bitfield */
347
+ total_bits = (temp_upper + 1) * 8;
348
+ start_bits = bit_offset % 8;
349
+ start_mask = 0xFF << (8 - start_bits);
350
+ end_bits = total_bits - start_bits - bit_size;
351
+ end_mask = 0xFF >> (8 - end_bits);
352
+
353
+ /* Shift to the right position */
354
+ unsigned_shift_byte_array(write_value, num_bytes, start_bits);
355
+
356
+ if (endianness == symbol_LITTLE_ENDIAN)
357
+ {
358
+ /* Mask in wanted bits at beginning */
359
+ write_value[0] |= buffer[upper_bound] & start_mask;
360
+
361
+ /* Mask in wanted bits at the end */
362
+ write_value[temp_upper] |= buffer[lower_bound] & end_mask;
363
+
364
+ reverse_bytes(write_value, num_bytes);
365
+ }
366
+ else
367
+ {
368
+ /* Mask in wanted bits at beginning */
369
+ write_value[0] |= buffer[lower_bound] & start_mask;
370
+
371
+ /* Mask in wanted bits at the end */
372
+ write_value[temp_upper] |= buffer[upper_bound] & end_mask;
373
+ }
374
+
375
+ /* Write the bytes into the buffer */
376
+ memcpy(&buffer[lower_bound], write_value, num_bytes);
377
+ }
378
+
379
+ /* Check the bit size and bit offset for problems. Recalulate the bit offset
380
+ * and return back through the passed in pointer. */
381
+ static void check_bit_offset_and_size(VALUE self, VALUE type_param, VALUE bit_offset_param, VALUE bit_size_param, VALUE data_type_param, VALUE buffer_param, int *new_bit_offset)
382
+ {
383
+ int bit_offset = NUM2INT(bit_offset_param);
384
+ int bit_size = NUM2INT(bit_size_param);
385
+
386
+ if ((bit_size <= 0) && (data_type_param != symbol_STRING) && (data_type_param != symbol_BLOCK))
387
+ {
388
+ rb_raise(rb_eArgError, "bit_size %d must be positive for data types other than :STRING and :BLOCK", bit_size);
389
+ }
390
+
391
+ if ((bit_size <= 0) && (bit_offset < 0))
392
+ {
393
+ rb_raise(rb_eArgError, "negative or zero bit_sizes (%d) cannot be given with negative bit_offsets (%d)", bit_size, bit_offset);
394
+ }
395
+
396
+ if (bit_offset < 0)
397
+ {
398
+ bit_offset = ((int)(RSTRING_LEN(buffer_param) * 8) + bit_offset);
399
+ if (bit_offset < 0)
400
+ {
401
+ rb_funcall(self, id_method_raise_buffer_error, 5, type_param, buffer_param, data_type_param, bit_offset_param, bit_size_param);
402
+ }
403
+ }
404
+
405
+ *new_bit_offset = bit_offset;
406
+ }
407
+
408
+ /* Returns true if the bit_size is 8, 16, 32, or 64 */
409
+ static int even_bit_size(int bit_size)
410
+ {
411
+ return ((bit_size == 8) || (bit_size == 16) || (bit_size == 32) || (bit_size == 64));
412
+ }
413
+
414
+ /* Calculate the bounds of the string to access the item based on the bit_offset and bit_size.
415
+ * Also determine if the buffer size is sufficient. */
416
+ static int check_bounds_and_buffer_size(int bit_offset, int bit_size, int buffer_length, VALUE endianness, VALUE data_type, int *lower_bound, int *upper_bound)
417
+ {
418
+ int result = 1; /* Assume ok */
419
+
420
+ /* Define bounds of string to access this item */
421
+ *lower_bound = bit_offset / 8;
422
+ *upper_bound = (bit_offset + bit_size - 1) / 8;
423
+
424
+ /* Sanity check buffer size */
425
+ if (*upper_bound >= buffer_length)
426
+ {
427
+ /* If it's not the special case of little endian bit field then we fail and return 0 */
428
+ if (!((endianness == symbol_LITTLE_ENDIAN) &&
429
+ ((data_type == symbol_INT) || (data_type == symbol_UINT)) &&
430
+ /* Not byte aligned with an even bit size */
431
+ (!((BYTE_ALIGNED(bit_offset)) && (even_bit_size(bit_size)))) &&
432
+ (*lower_bound < buffer_length)))
433
+ {
434
+ result = 0;
435
+ }
436
+ }
437
+ return result;
438
+ }
439
+
440
+ /*
441
+ * Reads binary data of any data type from a buffer
442
+ *
443
+ * @param bit_offset [Integer] Bit offset to the start of the item. A
444
+ * negative number means to offset from the end of the buffer.
445
+ * @param bit_size [Integer] Size of the item in bits
446
+ * @param data_type [Symbol] {DATA_TYPES}
447
+ * @param buffer [String] Binary string buffer to read from
448
+ * @param endianness [Symbol] {ENDIANNESS}
449
+ * @return [Integer] value read from the buffer
450
+ */
451
+ static VALUE binary_accessor_read(VALUE self, VALUE param_bit_offset, VALUE param_bit_size, VALUE param_data_type, VALUE param_buffer, VALUE param_endianness)
452
+ {
453
+ /* Convert Parameters to C Data Types */
454
+ int bit_offset = FIX2INT(param_bit_offset);
455
+ int bit_size = FIX2INT(param_bit_size);
456
+
457
+ /* Local Variables */
458
+ int given_bit_offset = bit_offset;
459
+ int given_bit_size = bit_size;
460
+ signed char signed_char_value = 0;
461
+ unsigned char unsigned_char_value = 0;
462
+ signed short signed_short_value = 0;
463
+ unsigned short unsigned_short_value = 0;
464
+ signed int signed_int_value = 0;
465
+ signed long signed_long_value = 0;
466
+ unsigned int unsigned_int_value = 0;
467
+ signed long long signed_long_long_value = 0;
468
+ unsigned long long unsigned_long_long_value = 0;
469
+ unsigned char *unsigned_char_array = NULL;
470
+ int array_length = 0;
471
+ char *string = NULL;
472
+ int string_length = 0;
473
+ float float_value = 0.0;
474
+ double double_value = 0.0;
475
+ int shift_needed = 0;
476
+ int shift_count = 0;
477
+ int index = 0;
478
+ int num_bits = 0;
479
+ int num_bytes = 0;
480
+ int num_words = 0;
481
+ int upper_bound = 0;
482
+ int lower_bound = 0;
483
+ volatile VALUE temp_value = Qnil;
484
+ volatile VALUE return_value = Qnil;
485
+
486
+ unsigned char *buffer = NULL;
487
+ long buffer_length = 0;
488
+
489
+ Check_Type(param_buffer, T_STRING);
490
+ buffer = (unsigned char *)RSTRING_PTR(param_buffer);
491
+ buffer_length = RSTRING_LEN(param_buffer);
492
+
493
+ check_bit_offset_and_size(self, symbol_read, param_bit_offset, param_bit_size,
494
+ param_data_type, param_buffer, &bit_offset);
495
+
496
+ /* If passed a negative bit size with strings or blocks
497
+ * recalculate based on the buffer length */
498
+ if ((bit_size <= 0) && ((param_data_type == symbol_STRING) || (param_data_type == symbol_BLOCK)))
499
+ {
500
+ bit_size = (((int)buffer_length * 8) - bit_offset + bit_size);
501
+ if (bit_size == 0)
502
+ {
503
+ return rb_str_new2("");
504
+ }
505
+ else if (bit_size < 0)
506
+ {
507
+ rb_funcall(self, id_method_raise_buffer_error, 5, symbol_read, param_buffer, param_data_type, param_bit_offset, param_bit_size);
508
+ }
509
+ }
510
+
511
+ if (!check_bounds_and_buffer_size(bit_offset, bit_size, (int)buffer_length, param_endianness, param_data_type, &lower_bound, &upper_bound))
512
+ {
513
+ rb_funcall(self, id_method_raise_buffer_error, 5, symbol_read, param_buffer, param_data_type, param_bit_offset, param_bit_size);
514
+ }
515
+
516
+ if ((param_data_type == symbol_STRING) || (param_data_type == symbol_BLOCK))
517
+ {
518
+ /*#######################################
519
+ *# Handle :STRING and :BLOCK data types
520
+ *#######################################*/
521
+
522
+ if (BYTE_ALIGNED(bit_offset))
523
+ {
524
+ string_length = upper_bound - lower_bound + 1;
525
+ string = malloc(string_length + 1);
526
+ if (string == NULL)
527
+ {
528
+ rb_raise(rb_eNoMemError, "malloc of %d returned NULL", string_length + 1);
529
+ }
530
+ memcpy(string, buffer + lower_bound, string_length);
531
+ string[string_length] = 0;
532
+ if (param_data_type == symbol_STRING)
533
+ {
534
+ return_value = rb_str_new2(string);
535
+ }
536
+ else /* param_data_type == symbol_BLOCK */
537
+ {
538
+ return_value = rb_str_new(string, string_length);
539
+ }
540
+ free(string);
541
+ }
542
+ else
543
+ {
544
+ rb_raise(rb_eArgError, "bit_offset %d is not byte aligned for data_type %s", given_bit_offset, RSTRING_PTR(rb_funcall(param_data_type, id_method_to_s, 0)));
545
+ }
546
+ }
547
+ else if (param_data_type == symbol_INT)
548
+ {
549
+ /*###################################
550
+ *# Handle :INT data type
551
+ *###################################*/
552
+
553
+ if ((BYTE_ALIGNED(bit_offset)) && (even_bit_size(bit_size)))
554
+ {
555
+ /*###########################################################
556
+ *# Handle byte-aligned 8, 16, 32, and 64 bit :INT
557
+ *###########################################################*/
558
+
559
+ switch (bit_size)
560
+ {
561
+ case 8:
562
+ signed_char_value = *((signed char *)&buffer[lower_bound]);
563
+ return_value = INT2FIX(signed_char_value);
564
+ break;
565
+ case 16:
566
+ read_aligned_16(lower_bound, upper_bound, param_endianness, buffer, (unsigned char *)&signed_short_value);
567
+ return_value = INT2FIX(signed_short_value);
568
+ break;
569
+ case 32:
570
+ read_aligned_32(lower_bound, upper_bound, param_endianness, buffer, (unsigned char *)&signed_int_value);
571
+ return_value = INT2NUM(signed_int_value);
572
+ break;
573
+ case 64:
574
+ read_aligned_64(lower_bound, upper_bound, param_endianness, buffer, (unsigned char *)&signed_long_long_value);
575
+ return_value = LL2NUM(signed_long_long_value);
576
+ break;
577
+ }
578
+ }
579
+ else
580
+ {
581
+ string_length = ((bit_size - 1) / 8) + 1;
582
+ array_length = string_length + 4; /* Required number of bytes plus slack */
583
+ unsigned_char_array = (unsigned char *)malloc(array_length);
584
+ if (unsigned_char_array == NULL)
585
+ {
586
+ rb_raise(rb_eNoMemError, "malloc of %d returned NULL", array_length);
587
+ }
588
+ read_bitfield(lower_bound, upper_bound, bit_offset, bit_size, given_bit_offset, given_bit_size, param_endianness, buffer, (int)buffer_length, unsigned_char_array);
589
+
590
+ num_words = ((string_length - 1) / 4) + 1;
591
+ num_bytes = num_words * 4;
592
+ num_bits = num_bytes * 8;
593
+ shift_needed = num_bits - bit_size;
594
+ shift_count = shift_needed / 8;
595
+ shift_needed = shift_needed % 8;
596
+
597
+ if (bit_size > 1)
598
+ {
599
+ for (index = 0; index < shift_count; index++)
600
+ {
601
+ signed_right_shift_byte_array(unsigned_char_array, num_bytes, 8);
602
+ }
603
+
604
+ if (shift_needed > 0)
605
+ {
606
+ signed_right_shift_byte_array(unsigned_char_array, num_bytes, shift_needed);
607
+ }
608
+ }
609
+ else
610
+ {
611
+ for (index = 0; index < shift_count; index++)
612
+ {
613
+ unsigned_right_shift_byte_array(unsigned_char_array, num_bytes, 8);
614
+ }
615
+
616
+ if (shift_needed > 0)
617
+ {
618
+ unsigned_right_shift_byte_array(unsigned_char_array, num_bytes, shift_needed);
619
+ }
620
+ }
621
+
622
+ if (HOST_ENDIANNESS == symbol_LITTLE_ENDIAN)
623
+ {
624
+ for (index = 0; index < num_bytes; index += 4)
625
+ {
626
+ reverse_bytes(&(unsigned_char_array[index]), 4);
627
+ }
628
+ }
629
+
630
+ if (bit_size <= 31)
631
+ {
632
+ return_value = INT2FIX(*((int *)unsigned_char_array));
633
+ }
634
+ else if (bit_size == 32)
635
+ {
636
+ return_value = INT2NUM(*((int *)unsigned_char_array));
637
+ }
638
+ else
639
+ {
640
+ return_value = rb_int2big(*((int *)unsigned_char_array));
641
+ temp_value = INT2FIX(32);
642
+ for (index = 4; index < num_bytes; index += 4)
643
+ {
644
+ return_value = rb_big_lshift(return_value, temp_value);
645
+ if (FIXNUM_P(return_value))
646
+ {
647
+ signed_long_value = FIX2LONG(return_value);
648
+ return_value = rb_int2big(signed_long_value);
649
+ }
650
+ return_value = rb_big_plus(return_value, UINT2NUM(*((unsigned int *)&(unsigned_char_array[index]))));
651
+ if (FIXNUM_P(return_value))
652
+ {
653
+ signed_long_value = FIX2LONG(return_value);
654
+ return_value = rb_int2big(signed_long_value);
655
+ }
656
+ }
657
+ return_value = rb_big_norm(return_value);
658
+ }
659
+
660
+ free(unsigned_char_array);
661
+ }
662
+ }
663
+ else if (param_data_type == symbol_UINT)
664
+ {
665
+ /*###################################
666
+ *# Handle :UINT data type
667
+ *###################################*/
668
+
669
+ if ((BYTE_ALIGNED(bit_offset)) && (even_bit_size(bit_size)))
670
+ {
671
+ /*###########################################################
672
+ *# Handle byte-aligned 8, 16, 32, and 64 bit :UINT
673
+ *###########################################################*/
674
+
675
+ switch (bit_size)
676
+ {
677
+ case 8:
678
+ unsigned_char_value = buffer[lower_bound];
679
+ return_value = INT2FIX(unsigned_char_value);
680
+ break;
681
+ case 16:
682
+ read_aligned_16(lower_bound, upper_bound, param_endianness, buffer, (unsigned char *)&unsigned_short_value);
683
+ return_value = INT2FIX(unsigned_short_value);
684
+ break;
685
+ case 32:
686
+ read_aligned_32(lower_bound, upper_bound, param_endianness, buffer, (unsigned char *)&unsigned_int_value);
687
+ return_value = UINT2NUM(unsigned_int_value);
688
+ break;
689
+ case 64:
690
+ read_aligned_64(lower_bound, upper_bound, param_endianness, buffer, (unsigned char *)&unsigned_long_long_value);
691
+ return_value = ULL2NUM(unsigned_long_long_value);
692
+ break;
693
+ }
694
+ }
695
+ else
696
+ {
697
+ string_length = ((bit_size - 1) / 8) + 1;
698
+ array_length = string_length + 4; /* Required number of bytes plus slack */
699
+ unsigned_char_array = (unsigned char *)malloc(array_length);
700
+ if (unsigned_char_array == NULL)
701
+ {
702
+ rb_raise(rb_eNoMemError, "malloc of %d returned NULL", array_length);
703
+ }
704
+ read_bitfield(lower_bound, upper_bound, bit_offset, bit_size, given_bit_offset, given_bit_size, param_endianness, buffer, (int)buffer_length, unsigned_char_array);
705
+
706
+ num_words = ((string_length - 1) / 4) + 1;
707
+ num_bytes = num_words * 4;
708
+ num_bits = num_bytes * 8;
709
+ shift_needed = num_bits - bit_size;
710
+ shift_count = shift_needed / 8;
711
+ shift_needed = shift_needed % 8;
712
+
713
+ for (index = 0; index < shift_count; index++)
714
+ {
715
+ unsigned_right_shift_byte_array(unsigned_char_array, num_bytes, 8);
716
+ }
717
+
718
+ if (shift_needed > 0)
719
+ {
720
+ unsigned_right_shift_byte_array(unsigned_char_array, num_bytes, shift_needed);
721
+ }
722
+
723
+ if (HOST_ENDIANNESS == symbol_LITTLE_ENDIAN)
724
+ {
725
+ for (index = 0; index < num_bytes; index += 4)
726
+ {
727
+ reverse_bytes(&(unsigned_char_array[index]), 4);
728
+ }
729
+ }
730
+
731
+ if (bit_size <= 30)
732
+ {
733
+ return_value = INT2FIX(*((int *)unsigned_char_array));
734
+ }
735
+ else if (bit_size <= 32)
736
+ {
737
+ return_value = UINT2NUM(*((unsigned int *)unsigned_char_array));
738
+ }
739
+ else
740
+ {
741
+ return_value = rb_uint2big(*((unsigned int *)unsigned_char_array));
742
+ temp_value = INT2FIX(32);
743
+ for (index = 4; index < num_bytes; index += 4)
744
+ {
745
+ return_value = rb_big_lshift(return_value, temp_value);
746
+ if (FIXNUM_P(return_value))
747
+ {
748
+ signed_long_value = FIX2LONG(return_value);
749
+ return_value = rb_int2big(signed_long_value);
750
+ }
751
+ return_value = rb_big_plus(return_value, UINT2NUM(*((unsigned int *)&(unsigned_char_array[index]))));
752
+ if (FIXNUM_P(return_value))
753
+ {
754
+ signed_long_value = FIX2LONG(return_value);
755
+ return_value = rb_int2big(signed_long_value);
756
+ }
757
+ }
758
+ return_value = rb_big_norm(return_value);
759
+ }
760
+
761
+ free(unsigned_char_array);
762
+ }
763
+ }
764
+ else if (param_data_type == symbol_FLOAT)
765
+ {
766
+ /*##########################
767
+ *# Handle :FLOAT data type
768
+ *##########################*/
769
+
770
+ if (BYTE_ALIGNED(bit_offset))
771
+ {
772
+ switch (bit_size)
773
+ {
774
+ case 32:
775
+ read_aligned_32(lower_bound, upper_bound, param_endianness, buffer, (unsigned char *)&float_value);
776
+ return_value = rb_float_new(float_value);
777
+ break;
778
+
779
+ case 64:
780
+ read_aligned_64(lower_bound, upper_bound, param_endianness, buffer, (unsigned char *)&double_value);
781
+ return_value = rb_float_new(double_value);
782
+ break;
783
+
784
+ default:
785
+ rb_raise(rb_eArgError, "bit_size is %d but must be 32 or 64 for data_type %s", given_bit_size, RSTRING_PTR(rb_funcall(param_data_type, id_method_to_s, 0)));
786
+ break;
787
+ };
788
+ }
789
+ else
790
+ {
791
+ rb_raise(rb_eArgError, "bit_offset %d is not byte aligned for data_type %s", given_bit_offset, RSTRING_PTR(rb_funcall(param_data_type, id_method_to_s, 0)));
792
+ }
793
+ }
794
+ else
795
+ {
796
+ /*############################
797
+ *# Handle Unknown data types
798
+ *############################*/
799
+
800
+ rb_raise(rb_eArgError, "data_type %s is not recognized", RSTRING_PTR(rb_funcall(param_data_type, id_method_to_s, 0)));
801
+ }
802
+
803
+ return return_value;
804
+ }
805
+
806
+ static VALUE check_overflow(VALUE value, int bit_size, VALUE data_type, VALUE overflow)
807
+ {
808
+ volatile VALUE hex_max_value = Qnil;
809
+ volatile VALUE max_value = Qnil;
810
+ volatile VALUE min_value = INT2NUM(0); /* Default for UINT cases */
811
+
812
+ switch (bit_size)
813
+ {
814
+ case 8:
815
+ hex_max_value = MAX_UINT8;
816
+ if (data_type == symbol_INT)
817
+ {
818
+ min_value = MIN_INT8;
819
+ max_value = MAX_INT8;
820
+ }
821
+ else
822
+ {
823
+ max_value = MAX_UINT8;
824
+ }
825
+ break;
826
+ case 16:
827
+ hex_max_value = MAX_UINT16;
828
+ if (data_type == symbol_INT)
829
+ {
830
+ min_value = MIN_INT16;
831
+ max_value = MAX_INT16;
832
+ }
833
+ else
834
+ {
835
+ max_value = MAX_UINT16;
836
+ }
837
+ break;
838
+ case 32:
839
+ hex_max_value = MAX_UINT32;
840
+ if (data_type == symbol_INT)
841
+ {
842
+ min_value = MIN_INT32;
843
+ max_value = MAX_INT32;
844
+ }
845
+ else
846
+ {
847
+ max_value = MAX_UINT32;
848
+ }
849
+ break;
850
+ case 64:
851
+ hex_max_value = MAX_UINT64;
852
+ if (data_type == symbol_INT)
853
+ {
854
+ min_value = MIN_INT64;
855
+ max_value = MAX_INT64;
856
+ }
857
+ else
858
+ {
859
+ max_value = MAX_UINT64;
860
+ }
861
+ break;
862
+ default: /* Bitfield */
863
+ if (data_type == symbol_INT)
864
+ {
865
+ /* Note signed integers must allow up to the maximum unsigned value to support values given in hex */
866
+ if (bit_size > 1)
867
+ {
868
+ max_value = rb_big_pow(TO_BIGNUM(INT2NUM(2)), INT2NUM(bit_size - 1));
869
+ /* min_value = -(2 ** bit_size - 1) */
870
+ min_value = rb_big_minus(TO_BIGNUM(INT2NUM(0)), max_value);
871
+ /* max_value = (2 ** bit_size - 1) - 1 */
872
+ max_value = rb_big_minus(TO_BIGNUM(max_value), INT2NUM(1));
873
+ /* hex_max_value = (2 ** bit_size) - 1 */
874
+ hex_max_value = rb_big_pow(TO_BIGNUM(INT2NUM(2)), INT2NUM(bit_size));
875
+ hex_max_value = rb_big_minus(TO_BIGNUM(hex_max_value), INT2NUM(1));
876
+ }
877
+ else
878
+ { /* 1-bit signed */
879
+ min_value = INT2NUM(-1);
880
+ max_value = INT2NUM(1);
881
+ hex_max_value = INT2NUM(1);
882
+ }
883
+ }
884
+ else
885
+ {
886
+ max_value = rb_big_pow(TO_BIGNUM(INT2NUM(2)), INT2NUM(bit_size));
887
+ max_value = rb_big_minus(TO_BIGNUM(max_value), INT2NUM(1));
888
+ hex_max_value = max_value;
889
+ }
890
+ break;
891
+ }
892
+ /* Convert all to Bignum objects so we can do the math the same way */
893
+ value = TO_BIGNUM(value);
894
+ min_value = TO_BIGNUM(min_value);
895
+ max_value = TO_BIGNUM(max_value);
896
+ hex_max_value = TO_BIGNUM(hex_max_value);
897
+
898
+ if (overflow == symbol_TRUNCATE)
899
+ {
900
+ /* Note this will always convert to unsigned equivalent for signed integers */
901
+ value = rb_big_modulo(value, TO_BIGNUM(rb_big_plus(hex_max_value, INT2NUM(1))));
902
+ }
903
+ else
904
+ {
905
+ if (rb_big_cmp(value, max_value) == INT2FIX(1))
906
+ {
907
+ if (overflow == symbol_SATURATE)
908
+ {
909
+ value = max_value;
910
+ }
911
+ else
912
+ {
913
+ if ((overflow == symbol_ERROR) || (rb_big_cmp(value, hex_max_value) == INT2FIX(1)))
914
+ {
915
+ rb_raise(rb_eArgError, "value of %s invalid for %d-bit %s",
916
+ RSTRING_PTR(rb_funcall(value, id_method_to_s, 0)),
917
+ bit_size,
918
+ RSTRING_PTR(rb_funcall(data_type, id_method_to_s, 0)));
919
+ }
920
+ }
921
+ }
922
+ else if (rb_big_cmp(value, min_value) == INT2FIX(-1))
923
+ {
924
+ if (overflow == symbol_SATURATE)
925
+ {
926
+ value = min_value;
927
+ }
928
+ else
929
+ {
930
+ rb_raise(rb_eArgError, "value of %s invalid for %d-bit %s",
931
+ RSTRING_PTR(rb_funcall(value, id_method_to_s, 0)),
932
+ bit_size,
933
+ RSTRING_PTR(rb_funcall(data_type, id_method_to_s, 0)));
934
+ }
935
+ }
936
+ }
937
+
938
+ return rb_big_norm(value);
939
+ }
940
+
941
+ /*
942
+ * Writes binary data of any data type to a buffer
943
+ *
944
+ * @param bit_offset [Integer] Bit offset to the start of the item. A
945
+ * negative number means to offset from the end of the buffer.
946
+ * @param bit_size [Integer] Size of the item in bits
947
+ * @param data_type [Symbol] {DATA_TYPES}
948
+ * @param buffer [String] Binary string buffer to read from
949
+ * @param endianness [Symbol] {ENDIANNESS}
950
+ * @return [Integer] value read from the buffer
951
+ */
952
+ static VALUE binary_accessor_write(VALUE self, VALUE value, VALUE param_bit_offset, VALUE param_bit_size, VALUE param_data_type, VALUE param_buffer, VALUE param_endianness, VALUE param_overflow)
953
+ {
954
+ /* Convert Parameters to C Data Types */
955
+ int bit_offset = NUM2INT(param_bit_offset);
956
+ int bit_size = NUM2INT(param_bit_size);
957
+ /* Local Variables */
958
+ int given_bit_offset = bit_offset;
959
+ int given_bit_size = bit_size;
960
+ int upper_bound = 0;
961
+ int lower_bound = 0;
962
+ int end_bytes = 0;
963
+ int old_upper_bound = 0;
964
+ int byte_size = 0;
965
+
966
+ unsigned long long c_value = 0;
967
+ float float_value = 0.0;
968
+ double double_value = 0.0;
969
+
970
+ unsigned char *buffer = NULL;
971
+ long buffer_length = 0;
972
+ long value_length = 0;
973
+ volatile VALUE temp_shift = Qnil;
974
+ volatile VALUE temp_mask = Qnil;
975
+ volatile VALUE temp_result = Qnil;
976
+
977
+ int string_length = 0;
978
+ unsigned char *unsigned_char_array = NULL;
979
+ int array_length = 0;
980
+ int shift_needed = 0;
981
+ int shift_count = 0;
982
+ int index = 0;
983
+ int num_bits = 0;
984
+ int num_bytes = 0;
985
+ int num_words = 0;
986
+
987
+ Check_Type(param_buffer, T_STRING);
988
+ buffer = (unsigned char *)RSTRING_PTR(param_buffer);
989
+ buffer_length = RSTRING_LEN(param_buffer);
990
+
991
+ check_bit_offset_and_size(self, symbol_write, param_bit_offset, param_bit_size,
992
+ param_data_type, param_buffer, &bit_offset);
993
+
994
+ /* If passed a negative bit size with strings or blocks
995
+ * recalculate based on the value length in bytes */
996
+ if ((bit_size <= 0) && ((param_data_type == symbol_STRING) || (param_data_type == symbol_BLOCK)))
997
+ {
998
+ if (!RB_TYPE_P(value, T_STRING))
999
+ {
1000
+ value = rb_funcall(value, id_method_to_s, 0);
1001
+ }
1002
+ bit_size = (int)RSTRING_LEN(value) * 8;
1003
+ }
1004
+
1005
+ if ((!check_bounds_and_buffer_size(bit_offset, bit_size, (int)buffer_length, param_endianness, param_data_type, &lower_bound, &upper_bound)) && (given_bit_size > 0))
1006
+ {
1007
+ rb_funcall(self, id_method_raise_buffer_error, 5, symbol_write, param_buffer, param_data_type, param_bit_offset, param_bit_size);
1008
+ }
1009
+
1010
+ /* Check overflow type */
1011
+ if ((param_overflow != symbol_TRUNCATE) &&
1012
+ (param_overflow != symbol_SATURATE) &&
1013
+ (param_overflow != symbol_ERROR) &&
1014
+ (param_overflow != symbol_ERROR_ALLOW_HEX))
1015
+ {
1016
+ rb_raise(rb_eArgError, "unknown overflow type %s", RSTRING_PTR(rb_funcall(param_overflow, id_method_to_s, 0)));
1017
+ }
1018
+
1019
+ if ((param_data_type == symbol_STRING) || (param_data_type == symbol_BLOCK))
1020
+ {
1021
+ /*#######################################
1022
+ *# Handle :STRING and :BLOCK data types
1023
+ *#######################################*/
1024
+ /* Force value to be a string */
1025
+ if (!RB_TYPE_P(value, T_STRING))
1026
+ {
1027
+ value = rb_funcall(value, id_method_to_s, 0);
1028
+ }
1029
+
1030
+ if (BYTE_ALIGNED(bit_offset))
1031
+ {
1032
+ value_length = RSTRING_LEN(value);
1033
+
1034
+ if (given_bit_size <= 0)
1035
+ {
1036
+ end_bytes = -(given_bit_size / 8);
1037
+ old_upper_bound = (int)buffer_length - 1 - end_bytes;
1038
+ /* Lower bound + end_bytes can never be more than 1 byte outside of the given buffer */
1039
+ if ((lower_bound + end_bytes) > buffer_length)
1040
+ {
1041
+ rb_funcall(self, id_method_raise_buffer_error, 5, symbol_write, param_buffer, param_data_type, param_bit_offset, param_bit_size);
1042
+ }
1043
+
1044
+ if (old_upper_bound < lower_bound)
1045
+ {
1046
+ /* String was completely empty */
1047
+ if (end_bytes > 0)
1048
+ {
1049
+ /* Preserve bytes at end of buffer */
1050
+ rb_str_concat(param_buffer, rb_str_times(ZERO_STRING, INT2FIX(value_length)));
1051
+ buffer = (unsigned char *)RSTRING_PTR(param_buffer);
1052
+ memmove((buffer + lower_bound + value_length), (buffer + lower_bound), end_bytes);
1053
+ }
1054
+ }
1055
+ else if (bit_size == 0)
1056
+ {
1057
+ /* Remove entire string */
1058
+ rb_str_update(param_buffer, lower_bound, old_upper_bound - lower_bound + 1, rb_str_new2(""));
1059
+ }
1060
+ else if (upper_bound < old_upper_bound)
1061
+ {
1062
+ /* Remove extra bytes from old string */
1063
+ rb_str_update(param_buffer, upper_bound + 1, old_upper_bound - upper_bound, rb_str_new2(""));
1064
+ }
1065
+ else if ((upper_bound > old_upper_bound) && (end_bytes > 0))
1066
+ {
1067
+ /* Preserve bytes at end of buffer */
1068
+ rb_str_concat(param_buffer, rb_str_times(ZERO_STRING, INT2FIX(upper_bound - old_upper_bound)));
1069
+ buffer = (unsigned char *)RSTRING_PTR(param_buffer);
1070
+ memmove((buffer + upper_bound + 1), (buffer + old_upper_bound + 1), end_bytes);
1071
+ }
1072
+ }
1073
+ else
1074
+ {
1075
+ byte_size = bit_size / 8;
1076
+ if (value_length < byte_size)
1077
+ {
1078
+ /* Pad the requested size with zeros.
1079
+ * Tell Ruby we are going to be modifying the buffer with a memset */
1080
+ rb_str_modify(param_buffer);
1081
+ memset(RSTRING_PTR(param_buffer) + lower_bound + value_length, 0, byte_size - value_length);
1082
+ }
1083
+ else if (value_length > byte_size)
1084
+ {
1085
+ if (param_overflow == symbol_TRUNCATE)
1086
+ {
1087
+ /* Resize the value to fit the field */
1088
+ rb_str_update(value, byte_size, RSTRING_LEN(value) - byte_size, rb_str_new2(""));
1089
+ }
1090
+ else
1091
+ {
1092
+ rb_raise(rb_eArgError, "value of %d bytes does not fit into %d bytes for data_type %s", (int)value_length, byte_size, RSTRING_PTR(rb_funcall(param_data_type, id_method_to_s, 0)));
1093
+ }
1094
+ }
1095
+ }
1096
+ if (bit_size != 0)
1097
+ {
1098
+ rb_str_update(param_buffer, lower_bound, RSTRING_LEN(value), value);
1099
+ }
1100
+ }
1101
+ else
1102
+ {
1103
+ rb_raise(rb_eArgError, "bit_offset %d is not byte aligned for data_type %s", given_bit_offset, RSTRING_PTR(rb_funcall(param_data_type, id_method_to_s, 0)));
1104
+ }
1105
+ }
1106
+ else if ((param_data_type == symbol_INT) || (param_data_type == symbol_UINT))
1107
+ {
1108
+ /*###################################
1109
+ *# Handle :INT data type
1110
+ *###################################*/
1111
+ value = rb_funcall(rb_mKernel, id_method_Integer, 1, value);
1112
+
1113
+ if ((BYTE_ALIGNED(bit_offset)) && (even_bit_size(bit_size)))
1114
+ {
1115
+ /*###########################################################
1116
+ *# Handle byte-aligned 8, 16, 32, and 64 bit
1117
+ *###########################################################*/
1118
+
1119
+ value = check_overflow(value, bit_size, param_data_type, param_overflow);
1120
+ switch (bit_size)
1121
+ {
1122
+ case 8:
1123
+ c_value = NUM2CHR(value);
1124
+ break;
1125
+ case 16:
1126
+ c_value = NUM2USHORT(value);
1127
+ break;
1128
+ case 32:
1129
+ c_value = NUM2UINT(value);
1130
+ break;
1131
+ case 64:
1132
+ c_value = NUM2ULL(value);
1133
+ break;
1134
+ }
1135
+ /* If the passed endianess doesn't match the host we reverse the bytes.
1136
+ * Then shift the result over so it's at the bottom of the long long value. */
1137
+ if (param_endianness != HOST_ENDIANNESS)
1138
+ {
1139
+ reverse_bytes((unsigned char *)&c_value, 8);
1140
+ c_value = (c_value >> (64 - bit_size));
1141
+ }
1142
+ /* Tell Ruby we are going to be modifying the buffer with a memcpy */
1143
+ rb_str_modify(param_buffer);
1144
+ memcpy((RSTRING_PTR(param_buffer) + lower_bound), &c_value, bit_size / 8);
1145
+ }
1146
+ else
1147
+ {
1148
+ /*###########################################################
1149
+ *# Handle bit fields
1150
+ *###########################################################*/
1151
+ value = check_overflow(value, bit_size, param_data_type, param_overflow);
1152
+
1153
+ string_length = ((bit_size - 1) / 8) + 1;
1154
+ array_length = string_length + 4; /* Required number of bytes plus slack */
1155
+ unsigned_char_array = (unsigned char *)malloc(array_length);
1156
+ if (unsigned_char_array == NULL)
1157
+ {
1158
+ rb_raise(rb_eNoMemError, "malloc of %d returned NULL", array_length);
1159
+ }
1160
+
1161
+ num_words = ((string_length - 1) / 4) + 1;
1162
+ num_bytes = num_words * 4;
1163
+ num_bits = num_bytes * 8;
1164
+ shift_needed = num_bits - bit_size;
1165
+ shift_count = shift_needed / 8;
1166
+ shift_needed = shift_needed % 8;
1167
+
1168
+ /* Convert value into array of bytes */
1169
+ if (bit_size <= 30)
1170
+ {
1171
+ *((int *)unsigned_char_array) = FIX2INT(value);
1172
+ }
1173
+ else if (bit_size <= 32)
1174
+ {
1175
+ *((unsigned int *)unsigned_char_array) = NUM2UINT(value);
1176
+ }
1177
+ else
1178
+ {
1179
+ temp_mask = UINT2NUM(0xFFFFFFFF);
1180
+ temp_shift = INT2FIX(32);
1181
+ temp_result = rb_big_and(TO_BIGNUM(value), temp_mask);
1182
+ /* Work around bug where rb_big_and will return Qfalse if given a first parameter of 0 */
1183
+ if (temp_result == Qfalse)
1184
+ {
1185
+ temp_result = INT2FIX(0);
1186
+ }
1187
+ *((unsigned int *)&(unsigned_char_array[num_bytes - 4])) = NUM2UINT(temp_result);
1188
+ for (index = num_bytes - 8; index >= 0; index -= 4)
1189
+ {
1190
+ value = rb_big_rshift(TO_BIGNUM(value), temp_shift);
1191
+ temp_result = rb_big_and(TO_BIGNUM(value), temp_mask);
1192
+ /* Work around bug where rb_big_and will return Qfalse if given a first parameter of 0 */
1193
+ if (temp_result == Qfalse)
1194
+ {
1195
+ temp_result = INT2FIX(0);
1196
+ }
1197
+ *((unsigned int *)&(unsigned_char_array[index])) = NUM2UINT(temp_result);
1198
+ }
1199
+ }
1200
+
1201
+ if (HOST_ENDIANNESS == symbol_LITTLE_ENDIAN)
1202
+ {
1203
+ for (index = 0; index < num_bytes; index += 4)
1204
+ {
1205
+ reverse_bytes(&(unsigned_char_array[index]), 4);
1206
+ }
1207
+ }
1208
+
1209
+ for (index = 0; index < shift_count; index++)
1210
+ {
1211
+ left_shift_byte_array(unsigned_char_array, num_bytes, 8);
1212
+ }
1213
+
1214
+ if (shift_needed > 0)
1215
+ {
1216
+ left_shift_byte_array(unsigned_char_array, num_bytes, shift_needed);
1217
+ }
1218
+
1219
+ rb_str_modify(param_buffer);
1220
+ write_bitfield(lower_bound, upper_bound, bit_offset, bit_size, given_bit_offset, given_bit_size, param_endianness, (unsigned char *)RSTRING_PTR(param_buffer), (int)buffer_length, unsigned_char_array);
1221
+
1222
+ free(unsigned_char_array);
1223
+ }
1224
+ }
1225
+ else if (param_data_type == symbol_FLOAT)
1226
+ {
1227
+ /*##########################
1228
+ *# Handle :FLOAT data type
1229
+ *##########################*/
1230
+ value = rb_funcall(rb_mKernel, id_method_Float, 1, value);
1231
+
1232
+ if (BYTE_ALIGNED(bit_offset))
1233
+ {
1234
+ switch (bit_size)
1235
+ {
1236
+ case 32:
1237
+ float_value = (float)RFLOAT_VALUE(value);
1238
+ if (param_endianness != HOST_ENDIANNESS)
1239
+ {
1240
+ reverse_bytes((unsigned char *)&float_value, 4);
1241
+ }
1242
+ rb_str_modify(param_buffer);
1243
+ memcpy((RSTRING_PTR(param_buffer) + lower_bound), &float_value, 4);
1244
+ break;
1245
+
1246
+ case 64:
1247
+ double_value = RFLOAT_VALUE(value);
1248
+ if (param_endianness != HOST_ENDIANNESS)
1249
+ {
1250
+ reverse_bytes((unsigned char *)&double_value, 8);
1251
+ }
1252
+ rb_str_modify(param_buffer);
1253
+ memcpy((RSTRING_PTR(param_buffer) + lower_bound), &double_value, 8);
1254
+ break;
1255
+
1256
+ default:
1257
+ rb_raise(rb_eArgError, "bit_size is %d but must be 32 or 64 for data_type %s", given_bit_size, RSTRING_PTR(rb_funcall(param_data_type, id_method_to_s, 0)));
1258
+ break;
1259
+ };
1260
+ }
1261
+ else
1262
+ {
1263
+ rb_raise(rb_eArgError, "bit_offset %d is not byte aligned for data_type %s", given_bit_offset, RSTRING_PTR(rb_funcall(param_data_type, id_method_to_s, 0)));
1264
+ }
1265
+ }
1266
+ else
1267
+ {
1268
+ /*############################
1269
+ *# Handle Unknown data types
1270
+ *############################*/
1271
+
1272
+ rb_raise(rb_eArgError, "data_type %s is not recognized", RSTRING_PTR(rb_funcall(param_data_type, id_method_to_s, 0)));
1273
+ }
1274
+
1275
+ return value;
1276
+ }
1277
+
1278
+ /*
1279
+ * Returns the actual length as an integer.
1280
+ *
1281
+ * get_int_length(self) #=> 324
1282
+ */
1283
+ static int get_int_length(VALUE self)
1284
+ {
1285
+ rb_funcall(self, id_method_allocate_buffer_if_needed, 0);
1286
+ return (int)RSTRING_LEN(rb_ivar_get(self, id_ivar_buffer));
1287
+ }
1288
+
1289
+ /*
1290
+ * Returns the actual structure length.
1291
+ *
1292
+ * structure.length #=> 324
1293
+ */
1294
+ static VALUE structure_length(VALUE self)
1295
+ {
1296
+ return INT2FIX(get_int_length(self));
1297
+ }
1298
+
1299
+ static VALUE read_item_internal(VALUE self, VALUE item, VALUE buffer)
1300
+ {
1301
+ volatile VALUE bit_offset = Qnil;
1302
+ volatile VALUE bit_size = Qnil;
1303
+ volatile VALUE data_type = Qnil;
1304
+ volatile VALUE array_size = Qnil;
1305
+ volatile VALUE endianness = Qnil;
1306
+
1307
+ data_type = rb_ivar_get(item, id_ivar_data_type);
1308
+ if (data_type == symbol_DERIVED)
1309
+ {
1310
+ return Qnil;
1311
+ }
1312
+
1313
+ if (!(RTEST(buffer)))
1314
+ {
1315
+ buffer = rb_funcall(self, id_method_allocate_buffer_if_needed, 0);
1316
+ }
1317
+ bit_offset = rb_ivar_get(item, id_ivar_bit_offset);
1318
+ bit_size = rb_ivar_get(item, id_ivar_bit_size);
1319
+ array_size = rb_ivar_get(item, id_ivar_array_size);
1320
+ endianness = rb_ivar_get(item, id_ivar_endianness);
1321
+ if (RTEST(array_size))
1322
+ {
1323
+ return rb_funcall(cBinaryAccessor, id_method_read_array, 6, bit_offset, bit_size, data_type, array_size, buffer, endianness);
1324
+ }
1325
+ else
1326
+ {
1327
+ return binary_accessor_read(cBinaryAccessor, bit_offset, bit_size, data_type, buffer, endianness);
1328
+ }
1329
+ }
1330
+
1331
+ /*
1332
+ * Read an item in the structure
1333
+ *
1334
+ * @param item [StructureItem] Instance of StructureItem or one of its subclasses
1335
+ * @param value_type [Symbol] Not used. Subclasses should overload this
1336
+ * parameter to check whether to perform conversions on the item.
1337
+ * @param buffer [String] The binary buffer to read the item from
1338
+ * @return Value based on the item definition. This could be a string, integer,
1339
+ * float, or array of values.
1340
+ */
1341
+ static VALUE read_item(int argc, VALUE *argv, VALUE self)
1342
+ {
1343
+ volatile VALUE item = Qnil;
1344
+ volatile VALUE buffer = Qnil;
1345
+
1346
+ switch (argc)
1347
+ {
1348
+ case 1:
1349
+ case 2:
1350
+ item = argv[0];
1351
+ buffer = rb_ivar_get(self, id_ivar_buffer);
1352
+ break;
1353
+ case 3:
1354
+ item = argv[0];
1355
+ buffer = argv[2];
1356
+ break;
1357
+ default:
1358
+ /* Invalid number of arguments given */
1359
+ rb_raise(rb_eArgError, "wrong number of arguments (%d for 1..3)", argc);
1360
+ break;
1361
+ };
1362
+
1363
+ return read_item_internal(self, item, buffer);
1364
+ }
1365
+
1366
+ /*
1367
+ * Comparison Operator based on bit_offset. This means that StructureItems
1368
+ * with different names or bit sizes are equal if they have the same bit
1369
+ * offset.
1370
+ */
1371
+ static VALUE structure_item_spaceship(VALUE self, VALUE other_item)
1372
+ {
1373
+ int bit_offset = 0;
1374
+ int other_bit_offset = 0;
1375
+ int bit_size = 0;
1376
+ int other_bit_size = 0;
1377
+ int create_index = 0;
1378
+ int other_create_index = 0;
1379
+ int have_create_index = 0;
1380
+ volatile VALUE v_create_index = Qnil;
1381
+ volatile VALUE v_other_create_index = Qnil;
1382
+
1383
+ if (!RTEST(rb_funcall(other_item, id_method_kind_of, 1, cStructureItem)))
1384
+ {
1385
+ return Qnil;
1386
+ }
1387
+
1388
+ bit_offset = FIX2INT(rb_ivar_get(self, id_ivar_bit_offset));
1389
+ other_bit_offset = FIX2INT(rb_ivar_get(other_item, id_ivar_bit_offset));
1390
+
1391
+ v_create_index = rb_ivar_get(self, id_ivar_create_index);
1392
+ v_other_create_index = rb_ivar_get(other_item, id_ivar_create_index);
1393
+ if (RTEST(v_create_index) && RTEST(v_other_create_index))
1394
+ {
1395
+ create_index = FIX2INT(v_create_index);
1396
+ other_create_index = FIX2INT(v_other_create_index);
1397
+ have_create_index = 1;
1398
+ }
1399
+
1400
+ /* Handle same bit offset case */
1401
+ if ((bit_offset == 0) && (other_bit_offset == 0))
1402
+ {
1403
+ /* Both bit_offsets are 0 so sort by bit_size
1404
+ * This allows derived items with bit_size of 0 to be listed first
1405
+ * Compare based on bit size */
1406
+ bit_size = FIX2INT(rb_ivar_get(self, id_ivar_bit_size));
1407
+ other_bit_size = FIX2INT(rb_ivar_get(other_item, id_ivar_bit_size));
1408
+ if (bit_size == other_bit_size)
1409
+ {
1410
+ if (have_create_index)
1411
+ {
1412
+ if (create_index <= other_create_index)
1413
+ {
1414
+ return INT2FIX(-1);
1415
+ }
1416
+ else
1417
+ {
1418
+ return INT2FIX(1);
1419
+ }
1420
+ }
1421
+ else
1422
+ {
1423
+ return INT2FIX(0);
1424
+ }
1425
+ }
1426
+ if (bit_size < other_bit_size)
1427
+ {
1428
+ return INT2FIX(-1);
1429
+ }
1430
+ else
1431
+ {
1432
+ return INT2FIX(1);
1433
+ }
1434
+ }
1435
+
1436
+ /* Handle different bit offsets */
1437
+ if (((bit_offset >= 0) && (other_bit_offset >= 0)) || ((bit_offset < 0) && (other_bit_offset < 0)))
1438
+ {
1439
+ /* Both Have Same Sign */
1440
+ if (bit_offset == other_bit_offset)
1441
+ {
1442
+ if (have_create_index)
1443
+ {
1444
+ if (create_index <= other_create_index)
1445
+ {
1446
+ return INT2FIX(-1);
1447
+ }
1448
+ else
1449
+ {
1450
+ return INT2FIX(1);
1451
+ }
1452
+ }
1453
+ else
1454
+ {
1455
+ return INT2FIX(0);
1456
+ }
1457
+ }
1458
+ else if (bit_offset < other_bit_offset)
1459
+ {
1460
+ return INT2FIX(-1);
1461
+ }
1462
+ else
1463
+ {
1464
+ return INT2FIX(1);
1465
+ }
1466
+ }
1467
+ else
1468
+ {
1469
+ /* Different Signs */
1470
+ if (bit_offset == other_bit_offset)
1471
+ {
1472
+ if (have_create_index)
1473
+ {
1474
+ if (create_index <= other_create_index)
1475
+ {
1476
+ return INT2FIX(-1);
1477
+ }
1478
+ else
1479
+ {
1480
+ return INT2FIX(1);
1481
+ }
1482
+ }
1483
+ else
1484
+ {
1485
+ return INT2FIX(0);
1486
+ }
1487
+ }
1488
+ else if (bit_offset < other_bit_offset)
1489
+ {
1490
+ return INT2FIX(1);
1491
+ }
1492
+ else
1493
+ {
1494
+ return INT2FIX(-1);
1495
+ }
1496
+ }
1497
+ }
1498
+
1499
+ /* Structure constructor
1500
+ *
1501
+ * @param default_endianness [Symbol] Must be one of
1502
+ * {BinaryAccessor::ENDIANNESS}. By default it uses
1503
+ * BinaryAccessor::HOST_ENDIANNESS to determine the endianness of the host platform.
1504
+ * @param buffer [String] Buffer used to store the structure
1505
+ * @param item_class [Class] Class used to instantiate new structure items.
1506
+ * Must be StructureItem or one of its subclasses.
1507
+ */
1508
+ static VALUE structure_initialize(int argc, VALUE *argv, VALUE self)
1509
+ {
1510
+ volatile VALUE default_endianness = Qnil;
1511
+ volatile VALUE buffer = Qnil;
1512
+ volatile VALUE item_class = Qnil;
1513
+
1514
+ switch (argc)
1515
+ {
1516
+ case 0:
1517
+ default_endianness = HOST_ENDIANNESS;
1518
+ buffer = Qnil;
1519
+ item_class = cStructureItem;
1520
+ break;
1521
+ case 1:
1522
+ default_endianness = argv[0];
1523
+ buffer = Qnil;
1524
+ item_class = cStructureItem;
1525
+ break;
1526
+ case 2:
1527
+ default_endianness = argv[0];
1528
+ buffer = argv[1];
1529
+ item_class = cStructureItem;
1530
+ break;
1531
+ case 3:
1532
+ default_endianness = argv[0];
1533
+ buffer = argv[1];
1534
+ item_class = argv[2];
1535
+ break;
1536
+ default:
1537
+ /* Invalid number of arguments given */
1538
+ rb_raise(rb_eArgError, "wrong number of arguments (%d for 0..3)", argc);
1539
+ break;
1540
+ };
1541
+
1542
+ if ((default_endianness == symbol_BIG_ENDIAN) || (default_endianness == symbol_LITTLE_ENDIAN))
1543
+ {
1544
+ rb_ivar_set(self, id_ivar_default_endianness, default_endianness);
1545
+ if (RTEST(buffer))
1546
+ {
1547
+ Check_Type(buffer, T_STRING);
1548
+ rb_funcall(buffer, id_method_force_encoding, 1, ASCII_8BIT_STRING);
1549
+ rb_ivar_set(self, id_ivar_buffer, buffer);
1550
+ }
1551
+ else
1552
+ {
1553
+ rb_ivar_set(self, id_ivar_buffer, Qnil);
1554
+ }
1555
+ rb_ivar_set(self, id_ivar_item_class, item_class);
1556
+ rb_ivar_set(self, id_ivar_items, rb_hash_new());
1557
+ rb_ivar_set(self, id_ivar_sorted_items, rb_ary_new());
1558
+ rb_ivar_set(self, id_ivar_defined_length, INT2FIX(0));
1559
+ rb_ivar_set(self, id_ivar_defined_length_bits, INT2FIX(0));
1560
+ rb_ivar_set(self, id_ivar_pos_bit_size, INT2FIX(0));
1561
+ rb_ivar_set(self, id_ivar_neg_bit_size, INT2FIX(0));
1562
+ rb_ivar_set(self, id_ivar_fixed_size, Qtrue);
1563
+ rb_ivar_set(self, id_ivar_short_buffer_allowed, Qfalse);
1564
+ rb_ivar_set(self, id_ivar_mutex, Qnil);
1565
+ }
1566
+ else
1567
+ {
1568
+ rb_raise(rb_eArgError, "Unknown endianness '%s', must be :BIG_ENDIAN or :LITTLE_ENDIAN", RSTRING_PTR(rb_funcall(default_endianness, id_method_to_s, 0)));
1569
+ }
1570
+
1571
+ return self;
1572
+ }
1573
+
1574
+ /*
1575
+ * Resize the buffer at least the defined length of the structure
1576
+ */
1577
+ static VALUE resize_buffer(VALUE self)
1578
+ {
1579
+ volatile VALUE buffer = rb_ivar_get(self, id_ivar_buffer);
1580
+ if (RTEST(buffer))
1581
+ {
1582
+ volatile VALUE value_defined_length = rb_ivar_get(self, id_ivar_defined_length);
1583
+ long defined_length = FIX2INT(value_defined_length);
1584
+ long current_length = RSTRING_LEN(buffer);
1585
+
1586
+ /* Extend data size */
1587
+ if (current_length < defined_length)
1588
+ {
1589
+ rb_str_concat(buffer, rb_str_times(ZERO_STRING, INT2FIX(defined_length - current_length)));
1590
+ }
1591
+ }
1592
+ else
1593
+ {
1594
+ rb_funcall(self, id_method_allocate_buffer_if_needed, 0);
1595
+ }
1596
+
1597
+ return self;
1598
+ }
1599
+
1600
+ /*
1601
+ * Initialize all Packet methods
1602
+ */
1603
+ void Init_structure(void)
1604
+ {
1605
+ int zero = 0;
1606
+ volatile VALUE zero_string = Qnil;
1607
+ volatile VALUE ascii_8bit_string = Qnil;
1608
+
1609
+ mOpenC3 = rb_define_module("OpenC3");
1610
+ cBinaryAccessor = rb_define_class_under(mOpenC3, "BinaryAccessor", rb_cObject);
1611
+
1612
+ id_method_to_s = rb_intern("to_s");
1613
+ id_method_raise_buffer_error = rb_intern("raise_buffer_error");
1614
+ id_method_read_array = rb_intern("read_array");
1615
+ id_method_force_encoding = rb_intern("force_encoding");
1616
+ id_method_freeze = rb_intern("freeze");
1617
+ id_method_slice = rb_intern("slice");
1618
+ id_method_reverse = rb_intern("reverse");
1619
+ id_method_Integer = rb_intern("Integer");
1620
+ id_method_Float = rb_intern("Float");
1621
+ id_method_kind_of = rb_intern("kind_of?");
1622
+ id_method_allocate_buffer_if_needed = rb_intern("allocate_buffer_if_needed");
1623
+
1624
+ MIN_INT8 = INT2NUM(-128);
1625
+ MAX_INT8 = INT2NUM(127);
1626
+ MAX_UINT8 = INT2NUM(255);
1627
+ MIN_INT16 = INT2NUM(-32768);
1628
+ MAX_INT16 = INT2NUM(32767);
1629
+ MAX_UINT16 = INT2NUM(65535);
1630
+ MIN_INT32 = rb_big_pow(TO_BIGNUM(INT2NUM(2)), INT2NUM(31));
1631
+ MIN_INT32 = rb_big_minus(TO_BIGNUM(INT2NUM(0)), MIN_INT32);
1632
+ MAX_INT32 = rb_big_pow(TO_BIGNUM(INT2NUM(2)), INT2NUM(31));
1633
+ MAX_INT32 = rb_big_minus(TO_BIGNUM(MAX_INT32), INT2NUM(1));
1634
+ MAX_UINT32 = rb_big_pow(TO_BIGNUM(INT2NUM(2)), INT2NUM(32));
1635
+ MAX_UINT32 = rb_big_minus(TO_BIGNUM(MAX_UINT32), INT2NUM(1));
1636
+ MIN_INT64 = rb_big_pow(TO_BIGNUM(INT2NUM(2)), INT2NUM(63));
1637
+ MIN_INT64 = rb_big_minus(TO_BIGNUM(INT2NUM(0)), MIN_INT64);
1638
+ MAX_INT64 = rb_big_pow(TO_BIGNUM(INT2NUM(2)), INT2NUM(63));
1639
+ MAX_INT64 = rb_big_minus(TO_BIGNUM(MAX_INT64), INT2NUM(1));
1640
+ MAX_UINT64 = rb_big_pow(TO_BIGNUM(INT2NUM(2)), INT2NUM(64));
1641
+ MAX_UINT64 = rb_big_minus(TO_BIGNUM(MAX_UINT64), INT2NUM(1));
1642
+ rb_define_const(cBinaryAccessor, "MIN_INT8", MIN_INT8);
1643
+ rb_define_const(cBinaryAccessor, "MAX_INT8", MAX_INT8);
1644
+ rb_define_const(cBinaryAccessor, "MAX_UINT8", MAX_UINT8);
1645
+ rb_define_const(cBinaryAccessor, "MIN_INT16", MIN_INT16);
1646
+ rb_define_const(cBinaryAccessor, "MAX_INT16", MAX_INT16);
1647
+ rb_define_const(cBinaryAccessor, "MAX_UINT16", MAX_UINT16);
1648
+ rb_define_const(cBinaryAccessor, "MIN_INT32", MIN_INT32);
1649
+ rb_define_const(cBinaryAccessor, "MAX_INT32", MAX_INT32);
1650
+ rb_define_const(cBinaryAccessor, "MAX_UINT32", MAX_UINT32);
1651
+ rb_define_const(cBinaryAccessor, "MIN_INT64", MIN_INT64);
1652
+ rb_define_const(cBinaryAccessor, "MAX_INT64", MAX_INT64);
1653
+ rb_define_const(cBinaryAccessor, "MAX_UINT64", MAX_UINT64);
1654
+
1655
+ id_ivar_buffer = rb_intern("@buffer");
1656
+ id_ivar_bit_offset = rb_intern("@bit_offset");
1657
+ id_ivar_bit_size = rb_intern("@bit_size");
1658
+ id_ivar_array_size = rb_intern("@array_size");
1659
+ id_ivar_endianness = rb_intern("@endianness");
1660
+ id_ivar_data_type = rb_intern("@data_type");
1661
+ id_ivar_default_endianness = rb_intern("@default_endianness");
1662
+ id_ivar_item_class = rb_intern("@item_class");
1663
+ id_ivar_items = rb_intern("@items");
1664
+ id_ivar_sorted_items = rb_intern("@sorted_items");
1665
+ id_ivar_defined_length = rb_intern("@defined_length");
1666
+ id_ivar_defined_length_bits = rb_intern("@defined_length_bits");
1667
+ id_ivar_pos_bit_size = rb_intern("@pos_bit_size");
1668
+ id_ivar_neg_bit_size = rb_intern("@neg_bit_size");
1669
+ id_ivar_fixed_size = rb_intern("@fixed_size");
1670
+ id_ivar_short_buffer_allowed = rb_intern("@short_buffer_allowed");
1671
+ id_ivar_mutex = rb_intern("@mutex");
1672
+ id_ivar_create_index = rb_intern("@create_index");
1673
+
1674
+ symbol_LITTLE_ENDIAN = ID2SYM(rb_intern("LITTLE_ENDIAN"));
1675
+ symbol_BIG_ENDIAN = ID2SYM(rb_intern("BIG_ENDIAN"));
1676
+ symbol_INT = ID2SYM(rb_intern("INT"));
1677
+ symbol_UINT = ID2SYM(rb_intern("UINT"));
1678
+ symbol_FLOAT = ID2SYM(rb_intern("FLOAT"));
1679
+ symbol_STRING = ID2SYM(rb_intern("STRING"));
1680
+ symbol_BLOCK = ID2SYM(rb_intern("BLOCK"));
1681
+ symbol_DERIVED = ID2SYM(rb_intern("DERIVED"));
1682
+ symbol_read = ID2SYM(rb_intern("read"));
1683
+ symbol_write = ID2SYM(rb_intern("write"));
1684
+ symbol_TRUNCATE = ID2SYM(rb_intern("TRUNCATE"));
1685
+ symbol_SATURATE = ID2SYM(rb_intern("SATURATE"));
1686
+ symbol_ERROR = ID2SYM(rb_intern("ERROR"));
1687
+ symbol_ERROR_ALLOW_HEX = ID2SYM(rb_intern("ERROR_ALLOW_HEX"));
1688
+
1689
+ if ((*((char *)&endianness_check)) == 1)
1690
+ {
1691
+ HOST_ENDIANNESS = symbol_LITTLE_ENDIAN;
1692
+ }
1693
+ else
1694
+ {
1695
+ HOST_ENDIANNESS = symbol_BIG_ENDIAN;
1696
+ }
1697
+
1698
+ rb_define_singleton_method(cBinaryAccessor, "read", binary_accessor_read, 5);
1699
+ rb_define_singleton_method(cBinaryAccessor, "write", binary_accessor_write, 7);
1700
+
1701
+ cStructure = rb_define_class_under(mOpenC3, "Structure", rb_cObject);
1702
+ id_const_ZERO_STRING = rb_intern("ZERO_STRING");
1703
+ zero_string = rb_str_new((char *)&zero, 1);
1704
+ rb_funcall(zero_string, id_method_freeze, 0);
1705
+ rb_const_set(cStructure, id_const_ZERO_STRING, zero_string);
1706
+ ZERO_STRING = rb_const_get(cStructure, id_const_ZERO_STRING);
1707
+ id_const_ASCII_8BIT_STRING = rb_intern("ASCII_8BIT_STRING");
1708
+ ascii_8bit_string = rb_str_new2("ASCII-8BIT");
1709
+ rb_funcall(ascii_8bit_string, id_method_freeze, 0);
1710
+ rb_const_set(cStructure, id_const_ASCII_8BIT_STRING, ascii_8bit_string);
1711
+ ASCII_8BIT_STRING = rb_const_get(cStructure, id_const_ASCII_8BIT_STRING);
1712
+ rb_define_method(cStructure, "initialize", structure_initialize, -1);
1713
+ rb_define_method(cStructure, "length", structure_length, 0);
1714
+ rb_define_method(cStructure, "read_item", read_item, -1);
1715
+ rb_define_method(cStructure, "resize_buffer", resize_buffer, 0);
1716
+
1717
+ cStructureItem = rb_define_class_under(mOpenC3, "StructureItem", rb_cObject);
1718
+ rb_define_method(cStructureItem, "<=>", structure_item_spaceship, 1);
1719
+ }