cosmos 3.3.3 → 3.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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);