cosmos 3.3.3 → 3.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (109) hide show
  1. checksums.yaml +4 -4
  2. data/.gitattributes +2 -0
  3. data/.travis.yml +2 -1
  4. data/Gemfile +4 -3
  5. data/Manifest.txt +22 -0
  6. data/autohotkey/tools/handbook_creator.ahk +9 -0
  7. data/autohotkey/tools/packet_viewer.ahk +4 -0
  8. data/bin/exchndl20-x64.dll +0 -0
  9. data/bin/exchndl20.dll +0 -0
  10. data/bin/exchndl21-x64.dll +0 -0
  11. data/bin/exchndl21.dll +0 -0
  12. data/bin/exchndl22-x64.dll +0 -0
  13. data/bin/exchndl22.dll +0 -0
  14. data/bin/mgwhelp-x64.dll +0 -0
  15. data/bin/mgwhelp.dll +0 -0
  16. data/cosmos.gemspec +1 -0
  17. data/data/crc.txt +30 -24
  18. data/demo/config/data/crc.txt +3 -3
  19. data/demo/config/tools/handbook_creator/templates/command_packets.html.erb +3 -1
  20. data/demo/config/tools/handbook_creator/templates/telemetry_packets.html.erb +3 -1
  21. data/demo/procedures/cosmos_api_test.rb +1 -1
  22. data/ext/cosmos/ext/low_fragmentation_array/low_fragmentation_array.c +4 -0
  23. data/ext/cosmos/ext/platform/platform.c +22 -2
  24. data/ext/cosmos/ext/structure/structure.c +631 -104
  25. data/ext/cosmos/ext/telemetry/telemetry.c +3 -2
  26. data/lib/cosmos/gui/line_graph/line_graph_drawing.rb +71 -92
  27. data/lib/cosmos/gui/line_graph/overview_graph.rb +1 -1
  28. data/lib/cosmos/gui/qt.rb +38 -24
  29. data/lib/cosmos/gui/text/ruby_editor.rb +1 -1
  30. data/lib/cosmos/packets/binary_accessor.rb +1 -288
  31. data/lib/cosmos/packets/telemetry.rb +2 -1
  32. data/lib/cosmos/script/cmd_tlm_server.rb +110 -0
  33. data/lib/cosmos/script/commands.rb +166 -0
  34. data/lib/cosmos/script/extract.rb +2 -2
  35. data/lib/cosmos/script/limits.rb +108 -0
  36. data/lib/cosmos/script/script.rb +28 -1487
  37. data/lib/cosmos/script/scripting.rb +889 -0
  38. data/lib/cosmos/script/telemetry.rb +174 -0
  39. data/lib/cosmos/script/tools.rb +138 -0
  40. data/lib/cosmos/streams/stream_protocol.rb +9 -6
  41. data/lib/cosmos/system/target.rb +55 -38
  42. data/lib/cosmos/tools/cmd_tlm_server/api.rb +6 -3
  43. data/lib/cosmos/tools/cmd_tlm_server/connections.rb +0 -1
  44. data/lib/cosmos/tools/cmd_tlm_server/gui/interfaces_tab.rb +17 -7
  45. data/lib/cosmos/tools/cmd_tlm_server/interface_thread.rb +15 -4
  46. data/lib/cosmos/tools/handbook_creator/handbook_creator.rb +15 -8
  47. data/lib/cosmos/tools/handbook_creator/handbook_creator_config.rb +41 -13
  48. data/lib/cosmos/tools/packet_viewer/packet_viewer.rb +18 -1
  49. data/lib/cosmos/tools/tlm_viewer/widgets/canvasline_widget.rb +1 -1
  50. data/lib/cosmos/tools/tlm_viewer/widgets/canvaslinevalue_widget.rb +1 -1
  51. data/lib/cosmos/tools/tlm_viewer/widgets/limitsbar_widget.rb +1 -1
  52. data/lib/cosmos/tools/tlm_viewer/widgets/rangebar_widget.rb +1 -1
  53. data/lib/cosmos/top_level.rb +1 -1
  54. data/lib/cosmos/utilities/ruby_lex_utils.rb +1 -1
  55. data/lib/cosmos/version.rb +5 -5
  56. data/spec/gui/line_graph/line_clip_spec.rb +6 -6
  57. data/spec/gui/qt_spec.rb +102 -0
  58. data/spec/interfaces/interface_spec.rb +9 -9
  59. data/spec/interfaces/linc_interface_spec.rb +72 -15
  60. data/spec/interfaces/serial_interface_spec.rb +9 -9
  61. data/spec/interfaces/simulated_target_interface_spec.rb +7 -7
  62. data/spec/interfaces/stream_interface_spec.rb +4 -4
  63. data/spec/interfaces/tcpip_client_interface_spec.rb +8 -8
  64. data/spec/interfaces/tcpip_server_interface_spec.rb +9 -9
  65. data/spec/interfaces/udp_interface_spec.rb +20 -20
  66. data/spec/io/json_drb_spec.rb +4 -4
  67. data/spec/io/raw_logger_pair_spec.rb +20 -20
  68. data/spec/io/raw_logger_spec.rb +3 -3
  69. data/spec/io/tcpip_server_spec.rb +9 -9
  70. data/spec/io/udp_sockets_spec.rb +2 -2
  71. data/spec/io/win32_serial_driver_spec.rb +2 -2
  72. data/spec/packets/binary_accessor_spec.rb +143 -6
  73. data/spec/packets/commands_spec.rb +5 -5
  74. data/spec/packets/limits_spec.rb +15 -15
  75. data/spec/packets/packet_config_spec.rb +19 -19
  76. data/spec/packets/packet_item_limits_spec.rb +3 -3
  77. data/spec/packets/packet_item_spec.rb +4 -4
  78. data/spec/packets/packet_spec.rb +33 -33
  79. data/spec/packets/structure_item_spec.rb +19 -19
  80. data/spec/packets/telemetry_spec.rb +6 -6
  81. data/spec/script/cmd_tlm_server_spec.rb +110 -0
  82. data/spec/script/commands_disconnect_spec.rb +270 -0
  83. data/spec/script/commands_spec.rb +288 -0
  84. data/spec/script/limits_spec.rb +153 -0
  85. data/spec/script/script_spec.rb +32 -696
  86. data/spec/script/scripting_spec.rb +436 -0
  87. data/spec/script/telemetry_spec.rb +130 -0
  88. data/spec/script/tools_spec.rb +117 -0
  89. data/spec/spec_helper.rb +10 -5
  90. data/spec/streams/preidentified_stream_protocol_spec.rb +4 -4
  91. data/spec/streams/serial_stream_spec.rb +8 -8
  92. data/spec/streams/stream_protocol_spec.rb +4 -4
  93. data/spec/streams/tcpip_client_stream_spec.rb +3 -3
  94. data/spec/streams/tcpip_socket_stream_spec.rb +7 -7
  95. data/spec/streams/template_stream_protocol_spec.rb +1 -1
  96. data/spec/system/system_spec.rb +6 -6
  97. data/spec/system/target_spec.rb +2 -0
  98. data/spec/tools/cmd_tlm_server/api_spec.rb +17 -17
  99. data/spec/tools/cmd_tlm_server/cmd_tlm_server_config_spec.rb +5 -5
  100. data/spec/tools/cmd_tlm_server/interface_thread_spec.rb +3 -3
  101. data/spec/top_level/top_level_spec.rb +8 -8
  102. data/spec/utilities/csv_spec.rb +3 -3
  103. data/spec/utilities/message_log_spec.rb +3 -3
  104. data/spec/utilities/ruby_lex_utils_spec.rb +7 -7
  105. data/test/performance/config/tools/launcher/launcher_threads.txt +8 -1
  106. data/test/performance/tools/CmdTlmServerMemProf +1 -1
  107. data/test/performance/tools/TlmGrapherMemProf +19 -0
  108. data/test/performance/tools/TlmGrapherMemProf.bat +59 -0
  109. metadata +38 -2
@@ -11,11 +11,27 @@
11
11
  #include "ruby.h"
12
12
  #include "stdio.h"
13
13
 
14
+ #define TO_BIGNUM(x) (FIXNUM_P(x) ? rb_int2big(FIX2LONG(x)) : x)
15
+ #define BYTE_ALIGNED(x) (((x) % 8) == 0)
16
+
14
17
  static const int endianness_check = 1;
15
18
  static VALUE HOST_ENDIANNESS = Qnil;
16
19
  static VALUE ZERO_STRING = Qnil;
17
20
  static VALUE ASCII_8BIT_STRING = Qnil;
18
21
 
22
+ static VALUE MIN_INT8 = Qnil;
23
+ static VALUE MAX_INT8 = Qnil;
24
+ static VALUE MAX_UINT8 = Qnil;
25
+ static VALUE MIN_INT16 = Qnil;
26
+ static VALUE MAX_INT16 = Qnil;
27
+ static VALUE MAX_UINT16 = Qnil;
28
+ static VALUE MIN_INT32 = Qnil;
29
+ static VALUE MAX_INT32 = Qnil;
30
+ static VALUE MAX_UINT32 = Qnil;
31
+ static VALUE MIN_INT64 = Qnil;
32
+ static VALUE MAX_INT64 = Qnil;
33
+ static VALUE MAX_UINT64 = Qnil;
34
+
19
35
  static VALUE mCosmos = Qnil;
20
36
  static VALUE cBinaryAccessor = Qnil;
21
37
  static VALUE cStructure = Qnil;
@@ -26,6 +42,10 @@ static ID id_method_raise_buffer_error = 0;
26
42
  static ID id_method_read_array = 0;
27
43
  static ID id_method_force_encoding = 0;
28
44
  static ID id_method_freeze = 0;
45
+ static ID id_method_slice = 0;
46
+ static ID id_method_reverse = 0;
47
+ static ID id_method_Integer = 0;
48
+ static ID id_method_Float = 0;
29
49
 
30
50
  static ID id_ivar_buffer = 0;
31
51
  static ID id_ivar_bit_offset = 0;
@@ -56,6 +76,11 @@ static VALUE symbol_STRING = Qnil;
56
76
  static VALUE symbol_BLOCK = Qnil;
57
77
  static VALUE symbol_DERIVED = Qnil;
58
78
  static VALUE symbol_read = Qnil;
79
+ static VALUE symbol_write = Qnil;
80
+ static VALUE symbol_TRUNCATE = Qnil;
81
+ static VALUE symbol_SATURATE = Qnil;
82
+ static VALUE symbol_ERROR = Qnil;
83
+ static VALUE symbol_ERROR_ALLOW_HEX = Qnil;
59
84
 
60
85
  /*
61
86
  * Perform an left bit shift on a string
@@ -267,6 +292,124 @@ static void read_bitfield(int lower_bound, int upper_bound, int bit_offset, int
267
292
  unsigned_shift_byte_array(read_value, num_bytes, -start_bits);
268
293
  }
269
294
 
295
+ 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) {
296
+ /* Local variables */
297
+ int num_bytes = 0;
298
+ int total_bits = 0;
299
+ int start_bits = 0;
300
+ int end_bits = 0;
301
+ int temp_upper = 0;
302
+ unsigned char start_mask = 0;
303
+ unsigned char end_mask = 0;
304
+
305
+ if (endianness == symbol_LITTLE_ENDIAN)
306
+ {
307
+ /* Bitoffset always refers to the most significant bit of a bitfield */
308
+ num_bytes = (((bit_offset % 8) + bit_size - 1) / 8) + 1;
309
+ upper_bound = bit_offset / 8;
310
+ lower_bound = upper_bound - num_bytes + 1;
311
+
312
+ if (lower_bound < 0) {
313
+ rb_raise(rb_eArgError, "LITTLE_ENDIAN bitfield with bit_offset %d and bit_size %d is invalid", given_bit_offset, given_bit_size);
314
+ }
315
+ }
316
+ else
317
+ {
318
+ num_bytes = upper_bound - lower_bound + 1;
319
+ }
320
+
321
+ /* Determine temp upper bound */
322
+ temp_upper = upper_bound - lower_bound;
323
+
324
+ /* Handle Bitfield */
325
+ total_bits = (temp_upper + 1) * 8;
326
+ start_bits = bit_offset % 8;
327
+ start_mask = 0xFF << (8 - start_bits);
328
+ end_bits = total_bits - start_bits - bit_size;
329
+ end_mask = 0xFF >> (8 - end_bits);
330
+
331
+ /* Shift to the right position */
332
+ unsigned_shift_byte_array(write_value, num_bytes, start_bits);
333
+
334
+ if (endianness == symbol_LITTLE_ENDIAN)
335
+ {
336
+ /* Mask in wanted bits at beginning */
337
+ write_value[0] |= buffer[upper_bound] & start_mask;
338
+
339
+ /* Mask in wanted bits at the end */
340
+ write_value[temp_upper] |= buffer[lower_bound] & end_mask;
341
+
342
+ reverse_bytes(write_value, num_bytes);
343
+ }
344
+ else
345
+ {
346
+ /* Mask in wanted bits at beginning */
347
+ write_value[0] |= buffer[lower_bound] & start_mask;
348
+
349
+ /* Mask in wanted bits at the end */
350
+ write_value[temp_upper] |= buffer[upper_bound] & end_mask;
351
+ }
352
+
353
+ /* Write the bytes into the buffer */
354
+ memcpy(&buffer[lower_bound], write_value, num_bytes);
355
+ }
356
+
357
+ /* Check the bit size and bit offset for problems. Recalulate the bit offset
358
+ * and return back through the passed in pointer. */
359
+ 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)
360
+ {
361
+ int bit_offset = NUM2INT(bit_offset_param);
362
+ int bit_size = NUM2INT(bit_size_param);
363
+
364
+ if ((bit_size <= 0) && (data_type_param != symbol_STRING) && (data_type_param != symbol_BLOCK)) {
365
+ rb_raise(rb_eArgError, "bit_size %d must be positive for data types other than :STRING and :BLOCK", bit_size);
366
+ }
367
+
368
+ if ((bit_size <= 0) && (bit_offset < 0)) {
369
+ rb_raise(rb_eArgError, "negative or zero bit_sizes (%d) cannot be given with negative bit_offsets (%d)", bit_size, bit_offset);
370
+ }
371
+
372
+ if (bit_offset < 0) {
373
+ bit_offset = ((RSTRING_LEN(buffer_param)* 8) + bit_offset);
374
+ if (bit_offset < 0) {
375
+ rb_funcall(self, id_method_raise_buffer_error, 5, type_param, buffer_param, data_type_param, bit_offset_param, bit_size_param);
376
+ }
377
+ }
378
+
379
+ *new_bit_offset = bit_offset;
380
+ }
381
+
382
+ /* Returns true if the bit_size is 8, 16, 32, or 64 */
383
+ static int even_bit_size(int bit_size)
384
+ {
385
+ return ((bit_size == 8) || (bit_size == 16) || (bit_size == 32) || (bit_size == 64));
386
+ }
387
+
388
+ /* Calculate the bounds of the string to access the item based on the bit_offset and bit_size.
389
+ * Also determine if the buffer size is sufficient. */
390
+ 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)
391
+ {
392
+ int result = 1; /* Assume ok */
393
+
394
+ /* Define bounds of string to access this item */
395
+ *lower_bound = bit_offset / 8;
396
+ *upper_bound = (bit_offset + bit_size - 1) / 8;
397
+
398
+ /* Sanity check buffer size */
399
+ if (*upper_bound >= buffer_length) {
400
+ /* If it's not the special case of little endian bit field then we fail and return 0 */
401
+ if (!( (endianness == symbol_LITTLE_ENDIAN) &&
402
+ ((data_type == symbol_INT) || (data_type == symbol_UINT)) &&
403
+ /* Not byte aligned with an even bit size */
404
+ (!( (BYTE_ALIGNED(bit_offset)) && (even_bit_size(bit_size)) )) &&
405
+ (*lower_bound < buffer_length)
406
+ )) {
407
+ result = 0;
408
+ }
409
+ }
410
+ return result;
411
+ }
412
+
270
413
  /*
271
414
  * Reads binary data of any data type from a buffer
272
415
  *
@@ -310,7 +453,6 @@ static VALUE binary_accessor_read(VALUE self, VALUE param_bit_offset, VALUE para
310
453
  int num_words = 0;
311
454
  int upper_bound = 0;
312
455
  int lower_bound = 0;
313
- int byte_aligned = 0;
314
456
  VALUE temp_value = Qnil;
315
457
  VALUE return_value = Qnil;
316
458
 
@@ -321,56 +463,31 @@ static VALUE binary_accessor_read(VALUE self, VALUE param_bit_offset, VALUE para
321
463
  buffer = (unsigned char*) RSTRING_PTR(param_buffer);
322
464
  buffer_length = RSTRING_LEN(param_buffer);
323
465
 
324
- /* Handle negative bit offsets */
325
- if (bit_offset < 0) {
326
- if (given_bit_size <= 0) {
327
- rb_raise(rb_eArgError, "negative or zero bit_sizes (%d) cannot be given with negative bit_offsets (%d)", given_bit_size, given_bit_offset);
328
- } else {
329
- bit_offset = (((int)buffer_length * 8) + bit_offset);
330
- if (bit_offset < 0) {
331
- rb_funcall(self, id_method_raise_buffer_error, 5, symbol_read, param_buffer, param_data_type, param_bit_offset, param_bit_size);
332
- }
333
- }
334
- }
466
+ check_bit_offset_and_size(self, symbol_read, param_bit_offset, param_bit_size,
467
+ param_data_type, param_buffer, &bit_offset);
335
468
 
336
- /* Handle negative and zero bit sizes */
337
- if (bit_size <= 0) {
338
- if ((param_data_type == symbol_STRING) || (param_data_type == symbol_BLOCK)) {
339
- bit_size = (((int)buffer_length * 8) - bit_offset + bit_size);
340
- if (bit_size == 0) {
341
- return rb_str_new2("");
342
- } else if (bit_size < 0) {
343
- rb_funcall(self, id_method_raise_buffer_error, 5, symbol_read, param_buffer, param_data_type, param_bit_offset, param_bit_size);
344
- }
345
- } else {
346
- rb_raise(rb_eArgError, "bit_size %d must be positive for data types other than :STRING and :BLOCK", given_bit_size);
469
+ /* If passed a negative bit size with strings or blocks
470
+ * recalculate based on the buffer length */
471
+ if ((bit_size <= 0) && ((param_data_type == symbol_STRING) || (param_data_type == symbol_BLOCK))) {
472
+ bit_size = (((int)buffer_length * 8) - bit_offset + bit_size);
473
+ if (bit_size == 0) {
474
+ return rb_str_new2("");
475
+ } else if (bit_size < 0) {
476
+ rb_funcall(self, id_method_raise_buffer_error, 5, symbol_read, param_buffer, param_data_type, param_bit_offset, param_bit_size);
347
477
  }
348
478
  }
349
479
 
350
- /* define bounds of string to access this item */
351
- lower_bound = (bit_offset / 8);
352
- upper_bound = ((bit_offset + bit_size - 1) / 8);
353
-
354
- /* Check for byte alignment */
355
- byte_aligned = ((bit_offset % 8) == 0);
356
-
357
- /* Sanity check buffer size */
358
- if (upper_bound >= buffer_length) {
359
- /* Check special case of little endian bit field */
360
- if ((param_endianness == symbol_LITTLE_ENDIAN) && ((param_data_type == symbol_INT) || (param_data_type == symbol_UINT)) && (!((byte_aligned) && ((bit_size == 8) || (bit_size == 16) || (bit_size == 32) || (bit_size == 64)))) && (lower_bound < buffer_length)) {
361
- /* Ok little endian bit field */
362
- } else {
363
- rb_funcall(self, id_method_raise_buffer_error, 5, symbol_read, param_buffer, param_data_type, param_bit_offset, param_bit_size);
364
- }
480
+ if (!check_bounds_and_buffer_size(bit_offset, bit_size, buffer_length, param_endianness, param_data_type, &lower_bound, &upper_bound))
481
+ {
482
+ rb_funcall(self, id_method_raise_buffer_error, 5, symbol_read, param_buffer, param_data_type, param_bit_offset, param_bit_size);
365
483
  }
366
484
 
367
485
  if ((param_data_type == symbol_STRING) || (param_data_type == symbol_BLOCK)) {
368
-
369
486
  /*#######################################
370
- *# Handle :STRING and :BLOCK data types
371
- *#######################################*/
487
+ *# Handle :STRING and :BLOCK data types
488
+ *#######################################*/
372
489
 
373
- if (byte_aligned) {
490
+ if (BYTE_ALIGNED(bit_offset)) {
374
491
  string_length = upper_bound - lower_bound + 1;
375
492
  string = malloc(string_length + 1);
376
493
  memcpy(string, buffer + lower_bound, string_length);
@@ -386,35 +503,33 @@ static VALUE binary_accessor_read(VALUE self, VALUE param_bit_offset, VALUE para
386
503
  }
387
504
 
388
505
  } else if (param_data_type == symbol_INT) {
389
-
390
506
  /*###################################
391
- *# Handle :INT data type
392
- *###################################*/
507
+ *# Handle :INT data type
508
+ *###################################*/
393
509
 
394
- if ((byte_aligned) && ((bit_size == 8) || (bit_size == 16) || (bit_size == 32) || (bit_size == 64))) {
510
+ if ((BYTE_ALIGNED(bit_offset)) && (even_bit_size(bit_size)))
511
+ {
395
512
  /*###########################################################
396
- *# Handle byte-aligned 8, 16, 32, and 64 bit :INT
397
- *###########################################################*/
513
+ *# Handle byte-aligned 8, 16, 32, and 64 bit :INT
514
+ *###########################################################*/
398
515
 
399
- if (bit_size == 8)
400
- {
401
- signed_char_value = *((signed char*) &buffer[lower_bound]);
402
- return_value = INT2FIX(signed_char_value);
403
- }
404
- else if (bit_size == 16)
405
- {
406
- read_aligned_16(lower_bound, upper_bound, param_endianness, buffer, (unsigned char*) &signed_short_value);
407
- return_value = INT2FIX(signed_short_value);
408
- }
409
- else if (bit_size == 32)
410
- {
411
- read_aligned_32(lower_bound, upper_bound, param_endianness, buffer, (unsigned char*) &signed_int_value);
412
- return_value = INT2NUM(signed_int_value);
413
- }
414
- else /* bit_size == 64 */
415
- {
416
- read_aligned_64(lower_bound, upper_bound, param_endianness, buffer, (unsigned char*) &signed_long_long_value);
417
- return_value = LL2NUM(signed_long_long_value);
516
+ switch (bit_size) {
517
+ case 8:
518
+ signed_char_value = *((signed char*) &buffer[lower_bound]);
519
+ return_value = INT2FIX(signed_char_value);
520
+ break;
521
+ case 16:
522
+ read_aligned_16(lower_bound, upper_bound, param_endianness, buffer, (unsigned char*) &signed_short_value);
523
+ return_value = INT2FIX(signed_short_value);
524
+ break;
525
+ case 32:
526
+ read_aligned_32(lower_bound, upper_bound, param_endianness, buffer, (unsigned char*) &signed_int_value);
527
+ return_value = INT2NUM(signed_int_value);
528
+ break;
529
+ case 64:
530
+ read_aligned_64(lower_bound, upper_bound, param_endianness, buffer, (unsigned char*) &signed_long_long_value);
531
+ return_value = LL2NUM(signed_long_long_value);
532
+ break;
418
533
  }
419
534
  } else {
420
535
  string_length = ((bit_size - 1)/ 8) + 1;
@@ -466,7 +581,7 @@ static VALUE binary_accessor_read(VALUE self, VALUE param_bit_offset, VALUE para
466
581
  signed_long_value = FIX2LONG(return_value);
467
582
  return_value = rb_int2big(signed_long_value);
468
583
  }
469
- return_value = rb_big_plus(return_value, rb_uint2big(*((unsigned int*) &(unsigned_char_array[index]))));
584
+ return_value = rb_big_plus(return_value, UINT2NUM(*((unsigned int*) &(unsigned_char_array[index]))));
470
585
  if (FIXNUM_P(return_value)) {
471
586
  signed_long_value = FIX2LONG(return_value);
472
587
  return_value = rb_int2big(signed_long_value);
@@ -479,35 +594,33 @@ static VALUE binary_accessor_read(VALUE self, VALUE param_bit_offset, VALUE para
479
594
  }
480
595
 
481
596
  } else if (param_data_type == symbol_UINT) {
482
-
483
597
  /*###################################
484
- *# Handle :UINT data type
485
- *###################################*/
598
+ *# Handle :UINT data type
599
+ *###################################*/
486
600
 
487
- if ((byte_aligned) && ((bit_size == 8) || (bit_size == 16) || (bit_size == 32) || (bit_size == 64))) {
601
+ if ((BYTE_ALIGNED(bit_offset)) && (even_bit_size(bit_size)))
602
+ {
488
603
  /*###########################################################
489
- *# Handle byte-aligned 8, 16, 32, and 64 bit :UINT
490
- *###########################################################*/
604
+ *# Handle byte-aligned 8, 16, 32, and 64 bit :UINT
605
+ *###########################################################*/
491
606
 
492
- if (bit_size == 8)
493
- {
494
- unsigned_char_value = buffer[lower_bound];
495
- return_value = INT2FIX(unsigned_char_value);
496
- }
497
- else if (bit_size == 16)
498
- {
499
- read_aligned_16(lower_bound, upper_bound, param_endianness, buffer, (unsigned char*) &unsigned_short_value);
500
- return_value = INT2FIX(unsigned_short_value);
501
- }
502
- else if (bit_size == 32)
503
- {
504
- read_aligned_32(lower_bound, upper_bound, param_endianness, buffer, (unsigned char*) &unsigned_int_value);
505
- return_value = UINT2NUM(unsigned_int_value);
506
- }
507
- else /* bit_size == 64 */
508
- {
509
- read_aligned_64(lower_bound, upper_bound, param_endianness, buffer, (unsigned char*) &unsigned_long_long_value);
510
- return_value = ULL2NUM(unsigned_long_long_value);
607
+ switch (bit_size) {
608
+ case 8:
609
+ unsigned_char_value = buffer[lower_bound];
610
+ return_value = INT2FIX(unsigned_char_value);
611
+ break;
612
+ case 16:
613
+ read_aligned_16(lower_bound, upper_bound, param_endianness, buffer, (unsigned char*) &unsigned_short_value);
614
+ return_value = INT2FIX(unsigned_short_value);
615
+ break;
616
+ case 32:
617
+ read_aligned_32(lower_bound, upper_bound, param_endianness, buffer, (unsigned char*) &unsigned_int_value);
618
+ return_value = UINT2NUM(unsigned_int_value);
619
+ break;
620
+ case 64:
621
+ read_aligned_64(lower_bound, upper_bound, param_endianness, buffer, (unsigned char*) &unsigned_long_long_value);
622
+ return_value = ULL2NUM(unsigned_long_long_value);
623
+ break;
511
624
  }
512
625
  } else {
513
626
  string_length = ((bit_size - 1)/ 8) + 1;
@@ -549,7 +662,7 @@ static VALUE binary_accessor_read(VALUE self, VALUE param_bit_offset, VALUE para
549
662
  signed_long_value = FIX2LONG(return_value);
550
663
  return_value = rb_int2big(signed_long_value);
551
664
  }
552
- return_value = rb_big_plus(return_value, rb_uint2big(*((unsigned int*) &(unsigned_char_array[index]))));
665
+ return_value = rb_big_plus(return_value, UINT2NUM(*((unsigned int*) &(unsigned_char_array[index]))));
553
666
  if (FIXNUM_P(return_value)) {
554
667
  signed_long_value = FIX2LONG(return_value);
555
668
  return_value = rb_int2big(signed_long_value);
@@ -562,12 +675,11 @@ static VALUE binary_accessor_read(VALUE self, VALUE param_bit_offset, VALUE para
562
675
  }
563
676
 
564
677
  } else if (param_data_type == symbol_FLOAT) {
565
-
566
678
  /*##########################
567
- *# Handle :FLOAT data type
568
- *##########################*/
679
+ *# Handle :FLOAT data type
680
+ *##########################*/
569
681
 
570
- if (byte_aligned) {
682
+ if (BYTE_ALIGNED(bit_offset)) {
571
683
  switch (bit_size) {
572
684
  case 32:
573
685
  read_aligned_32(lower_bound, upper_bound, param_endianness, buffer, (unsigned char*) &float_value);
@@ -588,10 +700,9 @@ static VALUE binary_accessor_read(VALUE self, VALUE param_bit_offset, VALUE para
588
700
  }
589
701
 
590
702
  } else {
591
-
592
703
  /*############################
593
- *# Handle Unknown data types
594
- *############################*/
704
+ *# Handle Unknown data types
705
+ *############################*/
595
706
 
596
707
  rb_raise(rb_eArgError, "data_type %s is not recognized", RSTRING_PTR(rb_funcall(param_data_type, id_method_to_s, 0)));
597
708
  }
@@ -599,6 +710,381 @@ static VALUE binary_accessor_read(VALUE self, VALUE param_bit_offset, VALUE para
599
710
  return return_value;
600
711
  }
601
712
 
713
+ static VALUE check_overflow(VALUE value, int bit_size, VALUE data_type, VALUE overflow)
714
+ {
715
+ VALUE hex_max_value = Qnil;
716
+ VALUE max_value = Qnil;
717
+ VALUE min_value = INT2NUM(0); /* Default for UINT cases */
718
+
719
+ switch (bit_size) {
720
+ case 8:
721
+ hex_max_value = MAX_UINT8;
722
+ if (data_type == symbol_INT) {
723
+ min_value = MIN_INT8;
724
+ max_value = MAX_INT8;
725
+ } else {
726
+ max_value = MAX_UINT8;
727
+ }
728
+ break;
729
+ case 16:
730
+ hex_max_value = MAX_UINT16;
731
+ if (data_type == symbol_INT) {
732
+ min_value = MIN_INT16;
733
+ max_value = MAX_INT16;
734
+ } else {
735
+ max_value = MAX_UINT16;
736
+ }
737
+ break;
738
+ case 32:
739
+ hex_max_value = MAX_UINT32;
740
+ if (data_type == symbol_INT) {
741
+ min_value = MIN_INT32;
742
+ max_value = MAX_INT32;
743
+ } else {
744
+ max_value = MAX_UINT32;
745
+ }
746
+ break;
747
+ case 64:
748
+ hex_max_value = MAX_UINT64;
749
+ if (data_type == symbol_INT) {
750
+ min_value = MIN_INT64;
751
+ max_value = MAX_INT64;
752
+ } else {
753
+ max_value = MAX_UINT64;
754
+ }
755
+ break;
756
+ default: /* Bitfield */
757
+ if (data_type == symbol_INT) {
758
+ /* Note signed integers must allow up to the maximum unsigned value to support values given in hex */
759
+ if (bit_size > 1) {
760
+ max_value = rb_big_pow(TO_BIGNUM(INT2NUM(2)), INT2NUM(bit_size - 1));
761
+ /* min_value = -(2 ** bit_size - 1) */
762
+ min_value = rb_big_minus(TO_BIGNUM(INT2NUM(0)), max_value);
763
+ /* max_value = (2 ** bit_size - 1) - 1 */
764
+ max_value = rb_big_minus(TO_BIGNUM(max_value), INT2NUM(1));
765
+ /* hex_max_value = (2 ** bit_size) - 1 */
766
+ hex_max_value = rb_big_pow(TO_BIGNUM(INT2NUM(2)), INT2NUM(bit_size));
767
+ hex_max_value = rb_big_minus(TO_BIGNUM(hex_max_value), INT2NUM(1));
768
+ } else { /* 1-bit signed */
769
+ min_value = INT2NUM(-1);
770
+ max_value = INT2NUM(1);
771
+ hex_max_value = INT2NUM(1);
772
+ }
773
+ } else {
774
+ max_value = rb_big_pow(TO_BIGNUM(INT2NUM(2)), INT2NUM(bit_size));
775
+ max_value = rb_big_minus(TO_BIGNUM(max_value), INT2NUM(1));
776
+ hex_max_value = max_value;
777
+ }
778
+ break;
779
+ }
780
+ /* Convert all to Bignum objects so we can do the math the same way */
781
+ value = TO_BIGNUM(value);
782
+ min_value = TO_BIGNUM(min_value);
783
+ max_value = TO_BIGNUM(max_value);
784
+ hex_max_value = TO_BIGNUM(hex_max_value);
785
+
786
+ if (overflow == symbol_TRUNCATE) {
787
+ /* Note this will always convert to unsigned equivalent for signed integers */
788
+ value = rb_big_modulo(value, TO_BIGNUM(rb_big_plus(hex_max_value, INT2NUM(1))));
789
+ } else {
790
+ if (rb_big_cmp(value, max_value) == INT2FIX(1)) {
791
+ if (overflow == symbol_SATURATE) {
792
+ value = max_value;
793
+ } else {
794
+ if ((overflow == symbol_ERROR) || (rb_big_cmp(value, hex_max_value) == INT2FIX(1))) {
795
+ rb_raise(rb_eArgError, "value of %s invalid for %d-bit %s",
796
+ RSTRING_PTR(rb_funcall(value, id_method_to_s, 0)),
797
+ bit_size,
798
+ RSTRING_PTR(rb_funcall(data_type, id_method_to_s, 0)));
799
+ }
800
+ }
801
+ } else if (rb_big_cmp(value, min_value) == INT2FIX(-1)) {
802
+ if (overflow == symbol_SATURATE) {
803
+ value = min_value;
804
+ } else {
805
+ rb_raise(rb_eArgError, "value of %s invalid for %d-bit %s",
806
+ RSTRING_PTR(rb_funcall(value, id_method_to_s, 0)),
807
+ bit_size,
808
+ RSTRING_PTR(rb_funcall(data_type, id_method_to_s, 0)));
809
+ }
810
+ }
811
+ }
812
+
813
+ return rb_big_norm(value);
814
+ }
815
+
816
+ /*
817
+ * Writes binary data of any data type to a buffer
818
+ *
819
+ * @param bit_offset [Integer] Bit offset to the start of the item. A
820
+ * negative number means to offset from the end of the buffer.
821
+ * @param bit_size [Integer] Size of the item in bits
822
+ * @param data_type [Symbol] {DATA_TYPES}
823
+ * @param buffer [String] Binary string buffer to read from
824
+ * @param endianness [Symbol] {ENDIANNESS}
825
+ * @return [Integer] value read from the buffer
826
+ */
827
+ 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)
828
+ {
829
+ /* Convert Parameters to C Data Types */
830
+ int bit_offset = NUM2INT(param_bit_offset);
831
+ int bit_size = NUM2INT(param_bit_size);
832
+ /* Local Variables */
833
+ int given_bit_offset = bit_offset;
834
+ int given_bit_size = bit_size;
835
+ int upper_bound = 0;
836
+ int lower_bound = 0;
837
+ int end_bytes = 0;
838
+ int old_upper_bound = 0;
839
+ int byte_size = 0;
840
+
841
+ unsigned long long c_value = 0;
842
+ float float_value = 0.0;
843
+ double double_value = 0.0;
844
+
845
+ unsigned char* buffer = NULL;
846
+ long buffer_length = 0;
847
+ long value_length = 0;
848
+ VALUE temp_shift = Qnil;
849
+ VALUE temp_mask = Qnil;
850
+ VALUE temp_result = Qnil;
851
+
852
+ int string_length = 0;
853
+ unsigned char* unsigned_char_array = NULL;
854
+ int array_length = 0;
855
+ int shift_needed = 0;
856
+ int shift_count = 0;
857
+ int index = 0;
858
+ int num_bits = 0;
859
+ int num_bytes = 0;
860
+ int num_words = 0;
861
+
862
+ Check_Type(param_buffer, T_STRING);
863
+ buffer = (unsigned char*) RSTRING_PTR(param_buffer);
864
+ buffer_length = RSTRING_LEN(param_buffer);
865
+
866
+ check_bit_offset_and_size(self, symbol_write, param_bit_offset, param_bit_size,
867
+ param_data_type, param_buffer, &bit_offset);
868
+
869
+ /* If passed a negative bit size with strings or blocks
870
+ * recalculate based on the value length in bytes */
871
+ if ((bit_size <= 0) && ((param_data_type == symbol_STRING) || (param_data_type == symbol_BLOCK))) {
872
+ if (!RB_TYPE_P(value, T_STRING)) {
873
+ value = rb_funcall(value, id_method_to_s, 0);
874
+ }
875
+ bit_size = RSTRING_LEN(value) * 8;
876
+ }
877
+
878
+ if ((!check_bounds_and_buffer_size(bit_offset, bit_size, buffer_length, param_endianness, param_data_type, &lower_bound, &upper_bound)) && (given_bit_size > 0)) {
879
+ rb_funcall(self, id_method_raise_buffer_error, 5, symbol_write, param_buffer, param_data_type, param_bit_offset, param_bit_size);
880
+ }
881
+
882
+ /* Check overflow type */
883
+ if ((param_overflow != symbol_TRUNCATE) &&
884
+ (param_overflow != symbol_SATURATE) &&
885
+ (param_overflow != symbol_ERROR) &&
886
+ (param_overflow != symbol_ERROR_ALLOW_HEX)) {
887
+ rb_raise(rb_eArgError, "unknown overflow type %s", RSTRING_PTR(rb_funcall(param_overflow, id_method_to_s, 0)));
888
+ }
889
+
890
+ if ((param_data_type == symbol_STRING) || (param_data_type == symbol_BLOCK)) {
891
+ /*#######################################
892
+ *# Handle :STRING and :BLOCK data types
893
+ *#######################################*/
894
+ /* Force value to be a string */
895
+ if (!RB_TYPE_P(value, T_STRING)) {
896
+ value = rb_funcall(value, id_method_to_s, 0);
897
+ }
898
+
899
+ if (BYTE_ALIGNED(bit_offset)) {
900
+ value_length = RSTRING_LEN(value);
901
+
902
+ if (given_bit_size <= 0) {
903
+ end_bytes = -(given_bit_size / 8);
904
+ old_upper_bound = buffer_length - 1 - end_bytes;
905
+ if (old_upper_bound < lower_bound) {
906
+ /* String was completely empty */
907
+ if (end_bytes > 0) {
908
+ /* Preserve bytes at end of buffer */
909
+ rb_str_concat(param_buffer, rb_str_times(ZERO_STRING, INT2FIX(value_length)));
910
+ buffer = (unsigned char*) RSTRING_PTR(param_buffer);
911
+ memmove((buffer + lower_bound + value_length), (buffer + lower_bound), value_length);
912
+ }
913
+ } else if (bit_size == 0) {
914
+ /* Remove entire string */
915
+ rb_str_update(param_buffer, lower_bound, old_upper_bound - lower_bound + 1, rb_str_new2(""));
916
+ } else if (upper_bound < old_upper_bound) {
917
+ /* Remove extra bytes from old string */
918
+ rb_str_update(param_buffer, upper_bound + 1, old_upper_bound + 1, rb_str_new2(""));
919
+ } else if ((upper_bound > old_upper_bound) && (end_bytes > 0)) {
920
+ /* Preserve bytes at end of buffer */
921
+ rb_str_concat(param_buffer, rb_str_times(ZERO_STRING, INT2FIX(upper_bound - old_upper_bound)));
922
+ buffer = (unsigned char*) RSTRING_PTR(param_buffer);
923
+ memmove((buffer + upper_bound + 1), (buffer + old_upper_bound + 1), upper_bound - old_upper_bound);
924
+ }
925
+ } else {
926
+ byte_size = bit_size / 8;
927
+ if (value_length < byte_size) {
928
+ /* Pad the requested size with zeros.
929
+ * Tell Ruby we are going to be modifying the buffer with a memset */
930
+ rb_str_modify(param_buffer);
931
+ memset(RSTRING_PTR(param_buffer) + lower_bound + value_length, 0, byte_size - value_length);
932
+ } else if (value_length > byte_size) {
933
+ if (param_overflow == symbol_TRUNCATE) {
934
+ /* Resize the value to fit the field */
935
+ rb_str_update(value, byte_size, RSTRING_LEN(value) - byte_size, rb_str_new2(""));
936
+ } else {
937
+ 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)));
938
+ }
939
+ }
940
+ }
941
+ if (bit_size != 0) {
942
+ rb_str_update(param_buffer, lower_bound, RSTRING_LEN(value), value);
943
+ }
944
+ } else {
945
+ 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)));
946
+ }
947
+
948
+ } else if ((param_data_type == symbol_INT) || (param_data_type == symbol_UINT)) {
949
+ /*###################################
950
+ *# Handle :INT data type
951
+ *###################################*/
952
+ value = rb_funcall(rb_mKernel, id_method_Integer, 1, value);
953
+
954
+ if ((BYTE_ALIGNED(bit_offset)) && (even_bit_size(bit_size)))
955
+ {
956
+ /*###########################################################
957
+ *# Handle byte-aligned 8, 16, 32, and 64 bit
958
+ *###########################################################*/
959
+
960
+ value = check_overflow(value, bit_size, param_data_type, param_overflow);
961
+ switch (bit_size) {
962
+ case 8:
963
+ c_value = NUM2CHR(value);
964
+ break;
965
+ case 16:
966
+ c_value = NUM2USHORT(value);
967
+ break;
968
+ case 32:
969
+ c_value = NUM2UINT(value);
970
+ break;
971
+ case 64:
972
+ c_value = NUM2ULL(value);
973
+ break;
974
+ }
975
+ /* If the passed endianess doesn't match the host we reverse the bytes.
976
+ * Then shift the result over so it's at the bottom of the long long value. */
977
+ if (param_endianness != HOST_ENDIANNESS) {
978
+ reverse_bytes((unsigned char *)&c_value, 8);
979
+ c_value = (c_value >> (64 - bit_size));
980
+ }
981
+ /* Tell Ruby we are going to be modifying the buffer with a memcpy */
982
+ rb_str_modify(param_buffer);
983
+ memcpy((RSTRING_PTR(param_buffer) + lower_bound), &c_value, bit_size / 8);
984
+
985
+ } else {
986
+ /*###########################################################
987
+ *# Handle bit fields
988
+ *###########################################################*/
989
+ value = check_overflow(value, bit_size, param_data_type, param_overflow);
990
+
991
+ string_length = ((bit_size - 1)/ 8) + 1;
992
+ array_length = string_length + 4; /* Required number of bytes plus slack */
993
+ unsigned_char_array = (unsigned char*) malloc(array_length);
994
+
995
+ num_words = ((string_length - 1) / 4) + 1;
996
+ num_bytes = num_words * 4;
997
+ num_bits = num_bytes * 8;
998
+ shift_needed = num_bits - bit_size;
999
+ shift_count = shift_needed / 8;
1000
+ shift_needed = shift_needed % 8;
1001
+
1002
+ /* Convert value into array of bytes */
1003
+ if (bit_size <= 30) {
1004
+ *((int *)unsigned_char_array) = FIX2INT(value);
1005
+ } else if (bit_size <= 32) {
1006
+ *((unsigned int *)unsigned_char_array) = NUM2UINT(value);
1007
+ } else {
1008
+ temp_mask = UINT2NUM(0xFFFFFFFF);
1009
+ temp_shift = INT2FIX(32);
1010
+ temp_result = rb_big_and(TO_BIGNUM(value), temp_mask);
1011
+ /* Work around bug where rb_big_and will return Qfalse if given a first parameter of 0 */
1012
+ if (temp_result == Qfalse) { temp_result = INT2FIX(0); }
1013
+ *((unsigned int *)&(unsigned_char_array[num_bytes - 4])) = NUM2UINT(temp_result);
1014
+ for (index = num_bytes - 8; index >= 0; index -= 4) {
1015
+ value = rb_big_rshift(TO_BIGNUM(value), temp_shift);
1016
+ temp_result = rb_big_and(TO_BIGNUM(value), temp_mask);
1017
+ /* Work around bug where rb_big_and will return Qfalse if given a first parameter of 0 */
1018
+ if (temp_result == Qfalse) { temp_result = INT2FIX(0); }
1019
+ *((unsigned int *)&(unsigned_char_array[index])) = NUM2UINT(temp_result);
1020
+ }
1021
+ }
1022
+
1023
+ if (HOST_ENDIANNESS == symbol_LITTLE_ENDIAN) {
1024
+ for (index = 0; index < num_bytes; index += 4) {
1025
+ reverse_bytes(&(unsigned_char_array[index]), 4);
1026
+ }
1027
+ }
1028
+
1029
+ for (index = 0; index < shift_count; index++) {
1030
+ left_shift_byte_array(unsigned_char_array, num_bytes, 8);
1031
+ }
1032
+
1033
+ if (shift_needed > 0) {
1034
+ left_shift_byte_array(unsigned_char_array, num_bytes, shift_needed);
1035
+ }
1036
+
1037
+ rb_str_modify(param_buffer);
1038
+ 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);
1039
+
1040
+ free(unsigned_char_array);
1041
+ }
1042
+
1043
+ } else if (param_data_type == symbol_FLOAT) {
1044
+ /*##########################
1045
+ *# Handle :FLOAT data type
1046
+ *##########################*/
1047
+ value = rb_funcall(rb_mKernel, id_method_Float, 1, value);
1048
+
1049
+ if (BYTE_ALIGNED(bit_offset)) {
1050
+ switch (bit_size) {
1051
+ case 32:
1052
+ float_value = (float)RFLOAT_VALUE(value);
1053
+ if (param_endianness != HOST_ENDIANNESS) {
1054
+ reverse_bytes((unsigned char *)&float_value, 4);
1055
+ }
1056
+ rb_str_modify(param_buffer);
1057
+ memcpy((RSTRING_PTR(param_buffer) + lower_bound), &float_value, 4);
1058
+ break;
1059
+
1060
+ case 64:
1061
+ double_value = RFLOAT_VALUE(value);
1062
+ if (param_endianness != HOST_ENDIANNESS) {
1063
+ reverse_bytes((unsigned char *)&double_value, 8);
1064
+ }
1065
+ rb_str_modify(param_buffer);
1066
+ memcpy((RSTRING_PTR(param_buffer) + lower_bound), &double_value, 8);
1067
+ break;
1068
+
1069
+ default:
1070
+ 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)));
1071
+ break;
1072
+ };
1073
+ } else {
1074
+ 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)));
1075
+ }
1076
+
1077
+ } else {
1078
+ /*############################
1079
+ *# Handle Unknown data types
1080
+ *############################*/
1081
+
1082
+ rb_raise(rb_eArgError, "data_type %s is not recognized", RSTRING_PTR(rb_funcall(param_data_type, id_method_to_s, 0)));
1083
+ }
1084
+
1085
+ return value;
1086
+ }
1087
+
602
1088
  /*
603
1089
  * Returns the actual length as an integer.
604
1090
  *
@@ -830,11 +1316,18 @@ void Init_structure (void)
830
1316
  {
831
1317
  int zero = 0;
832
1318
 
1319
+ mCosmos = rb_define_module("Cosmos");
1320
+ cBinaryAccessor = rb_define_class_under(mCosmos, "BinaryAccessor", rb_cObject);
1321
+
833
1322
  id_method_to_s = rb_intern("to_s");
834
1323
  id_method_raise_buffer_error = rb_intern("raise_buffer_error");
835
1324
  id_method_read_array = rb_intern("read_array");
836
1325
  id_method_force_encoding = rb_intern("force_encoding");
837
1326
  id_method_freeze = rb_intern("freeze");
1327
+ id_method_slice = rb_intern("slice");
1328
+ id_method_reverse = rb_intern("reverse");
1329
+ id_method_Integer = rb_intern("Integer");
1330
+ id_method_Float = rb_intern("Float");
838
1331
 
839
1332
  ASCII_8BIT_STRING = rb_str_new2("ASCII-8BIT");
840
1333
  rb_funcall(ASCII_8BIT_STRING, id_method_freeze, 0);
@@ -843,6 +1336,37 @@ void Init_structure (void)
843
1336
  rb_funcall(ZERO_STRING, id_method_freeze, 0);
844
1337
  id_const_ZERO_STRING = rb_intern("ZERO_STRING");
845
1338
 
1339
+ MIN_INT8 = INT2NUM(-128);
1340
+ MAX_INT8 = INT2NUM(127);
1341
+ MAX_UINT8 = INT2NUM(255);
1342
+ MIN_INT16 = INT2NUM(-32768);
1343
+ MAX_INT16 = INT2NUM(32767);
1344
+ MAX_UINT16 = INT2NUM(65535);
1345
+ MIN_INT32 = rb_big_pow(TO_BIGNUM(INT2NUM(2)), INT2NUM(31));
1346
+ MIN_INT32 = rb_big_minus(TO_BIGNUM(INT2NUM(0)), MIN_INT32);
1347
+ MAX_INT32 = rb_big_pow(TO_BIGNUM(INT2NUM(2)), INT2NUM(31));
1348
+ MAX_INT32 = rb_big_minus(TO_BIGNUM(MAX_INT32), INT2NUM(1));
1349
+ MAX_UINT32 = rb_big_pow(TO_BIGNUM(INT2NUM(2)), INT2NUM(32));
1350
+ MAX_UINT32 = rb_big_minus(TO_BIGNUM(MAX_UINT32), INT2NUM(1));
1351
+ MIN_INT64 = rb_big_pow(TO_BIGNUM(INT2NUM(2)), INT2NUM(63));
1352
+ MIN_INT64 = rb_big_minus(TO_BIGNUM(INT2NUM(0)), MIN_INT64);
1353
+ MAX_INT64 = rb_big_pow(TO_BIGNUM(INT2NUM(2)), INT2NUM(63));
1354
+ MAX_INT64 = rb_big_minus(TO_BIGNUM(MAX_INT64), INT2NUM(1));
1355
+ MAX_UINT64 = rb_big_pow(TO_BIGNUM(INT2NUM(2)), INT2NUM(64));
1356
+ MAX_UINT64 = rb_big_minus(TO_BIGNUM(MAX_UINT64), INT2NUM(1));
1357
+ rb_define_const(cBinaryAccessor, "MIN_INT8", MIN_INT8);
1358
+ rb_define_const(cBinaryAccessor, "MAX_INT8", MAX_INT8);
1359
+ rb_define_const(cBinaryAccessor, "MAX_UINT8", MAX_UINT8);
1360
+ rb_define_const(cBinaryAccessor, "MIN_INT16", MIN_INT16);
1361
+ rb_define_const(cBinaryAccessor, "MAX_INT16", MAX_INT16);
1362
+ rb_define_const(cBinaryAccessor, "MAX_UINT16", MAX_UINT16);
1363
+ rb_define_const(cBinaryAccessor, "MIN_INT32", MIN_INT32);
1364
+ rb_define_const(cBinaryAccessor, "MAX_INT32", MAX_INT32);
1365
+ rb_define_const(cBinaryAccessor, "MAX_UINT32", MAX_UINT32);
1366
+ rb_define_const(cBinaryAccessor, "MIN_INT64", MIN_INT64);
1367
+ rb_define_const(cBinaryAccessor, "MAX_INT64", MAX_INT64);
1368
+ rb_define_const(cBinaryAccessor, "MAX_UINT64", MAX_UINT64);
1369
+
846
1370
  id_ivar_buffer = rb_intern("@buffer");
847
1371
  id_ivar_bit_offset = rb_intern("@bit_offset");
848
1372
  id_ivar_bit_size = rb_intern("@bit_size");
@@ -870,6 +1394,11 @@ void Init_structure (void)
870
1394
  symbol_BLOCK = ID2SYM(rb_intern("BLOCK"));
871
1395
  symbol_DERIVED = ID2SYM(rb_intern("DERIVED"));
872
1396
  symbol_read = ID2SYM(rb_intern("read"));
1397
+ symbol_write = ID2SYM(rb_intern("write"));
1398
+ symbol_TRUNCATE = ID2SYM(rb_intern("TRUNCATE"));
1399
+ symbol_SATURATE = ID2SYM(rb_intern("SATURATE"));
1400
+ symbol_ERROR = ID2SYM(rb_intern("ERROR"));
1401
+ symbol_ERROR_ALLOW_HEX = ID2SYM(rb_intern("ERROR_ALLOW_HEX"));
873
1402
 
874
1403
  if ((*((char *) &endianness_check)) == 1) {
875
1404
  HOST_ENDIANNESS = symbol_LITTLE_ENDIAN;
@@ -877,10 +1406,8 @@ void Init_structure (void)
877
1406
  HOST_ENDIANNESS = symbol_BIG_ENDIAN;
878
1407
  }
879
1408
 
880
- mCosmos = rb_define_module("Cosmos");
881
-
882
- cBinaryAccessor = rb_define_class_under(mCosmos, "BinaryAccessor", rb_cObject);
883
1409
  rb_define_singleton_method(cBinaryAccessor, "read", binary_accessor_read, 5);
1410
+ rb_define_singleton_method(cBinaryAccessor, "write", binary_accessor_write, 7);
884
1411
 
885
1412
  cStructure = rb_define_class_under(mCosmos, "Structure", rb_cObject);
886
1413
  rb_const_set(cStructure, id_const_ZERO_STRING, ZERO_STRING);