bson 4.7.0 → 4.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (159) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +6 -2
  3. data/ext/bson/bson-endian.h +1 -1
  4. data/ext/bson/bson-native.h +16 -5
  5. data/ext/bson/bytebuf.c +1 -1
  6. data/ext/bson/endian.c +2 -1
  7. data/ext/bson/init.c +26 -3
  8. data/ext/bson/read.c +127 -33
  9. data/ext/bson/util.c +41 -1
  10. data/ext/bson/write.c +18 -14
  11. data/lib/bson.rb +4 -1
  12. data/lib/bson/active_support.rb +1 -1
  13. data/lib/bson/array.rb +34 -5
  14. data/lib/bson/binary.rb +42 -4
  15. data/lib/bson/boolean.rb +12 -3
  16. data/lib/bson/code.rb +16 -2
  17. data/lib/bson/code_with_scope.rb +32 -5
  18. data/lib/bson/config.rb +1 -1
  19. data/lib/bson/date.rb +1 -1
  20. data/lib/bson/date_time.rb +1 -1
  21. data/lib/bson/db_pointer.rb +110 -0
  22. data/lib/bson/decimal128.rb +16 -2
  23. data/lib/bson/decimal128/builder.rb +1 -1
  24. data/lib/bson/document.rb +1 -1
  25. data/lib/bson/environment.rb +2 -1
  26. data/lib/bson/error.rb +21 -0
  27. data/lib/bson/ext_json.rb +375 -0
  28. data/lib/bson/false_class.rb +1 -1
  29. data/lib/bson/float.rb +48 -2
  30. data/lib/bson/hash.rb +36 -5
  31. data/lib/bson/int32.rb +22 -2
  32. data/lib/bson/int64.rb +29 -4
  33. data/lib/bson/integer.rb +35 -1
  34. data/lib/bson/json.rb +1 -1
  35. data/lib/bson/max_key.rb +13 -1
  36. data/lib/bson/min_key.rb +13 -1
  37. data/lib/bson/nil_class.rb +4 -2
  38. data/lib/bson/object.rb +28 -1
  39. data/lib/bson/object_id.rb +16 -2
  40. data/lib/bson/open_struct.rb +1 -1
  41. data/lib/bson/regexp.rb +20 -3
  42. data/lib/bson/registry.rb +1 -1
  43. data/lib/bson/specialized.rb +4 -2
  44. data/lib/bson/string.rb +4 -2
  45. data/lib/bson/symbol.rb +93 -4
  46. data/lib/bson/time.rb +63 -4
  47. data/lib/bson/time_with_zone.rb +1 -1
  48. data/lib/bson/timestamp.rb +16 -2
  49. data/lib/bson/true_class.rb +1 -1
  50. data/lib/bson/undefined.rb +12 -1
  51. data/lib/bson/version.rb +2 -2
  52. data/spec/bson/array_spec.rb +1 -1
  53. data/spec/bson/binary_spec.rb +34 -4
  54. data/spec/bson/binary_uuid_spec.rb +1 -1
  55. data/spec/bson/boolean_spec.rb +1 -1
  56. data/spec/bson/code_spec.rb +1 -1
  57. data/spec/bson/code_with_scope_spec.rb +1 -1
  58. data/spec/bson/date_spec.rb +1 -1
  59. data/spec/bson/date_time_spec.rb +1 -1
  60. data/spec/bson/decimal128_spec.rb +1 -1
  61. data/spec/bson/document_spec.rb +1 -1
  62. data/spec/bson/ext_json_parse_spec.rb +308 -0
  63. data/spec/bson/false_class_spec.rb +1 -1
  64. data/spec/bson/float_spec.rb +37 -1
  65. data/spec/bson/hash_spec.rb +71 -1
  66. data/spec/bson/int32_spec.rb +21 -1
  67. data/spec/bson/int64_spec.rb +39 -1
  68. data/spec/bson/integer_spec.rb +27 -1
  69. data/spec/bson/json_spec.rb +1 -1
  70. data/spec/bson/max_key_spec.rb +1 -1
  71. data/spec/bson/min_key_spec.rb +1 -1
  72. data/spec/bson/nil_class_spec.rb +1 -1
  73. data/spec/bson/object_id_spec.rb +1 -1
  74. data/spec/bson/object_spec.rb +1 -1
  75. data/spec/bson/open_struct_spec.rb +1 -1
  76. data/spec/bson/raw_spec.rb +22 -1
  77. data/spec/bson/regexp_spec.rb +1 -1
  78. data/spec/bson/registry_spec.rb +1 -1
  79. data/spec/bson/string_spec.rb +1 -1
  80. data/spec/bson/symbol_raw_spec.rb +45 -0
  81. data/spec/bson/symbol_spec.rb +61 -1
  82. data/spec/bson/time_spec.rb +205 -2
  83. data/spec/bson/time_with_zone_spec.rb +1 -1
  84. data/spec/bson/timestamp_spec.rb +1 -1
  85. data/spec/bson/true_class_spec.rb +1 -1
  86. data/spec/bson/undefined_spec.rb +1 -1
  87. data/spec/bson_spec.rb +1 -1
  88. data/spec/{support → runners}/common_driver.rb +1 -1
  89. data/spec/runners/corpus.rb +185 -0
  90. data/spec/{support/corpus.rb → runners/corpus_legacy.rb} +41 -59
  91. data/spec/spec_helper.rb +10 -3
  92. data/spec/{bson/driver_bson_spec.rb → spec_tests/common_driver_spec.rb} +1 -0
  93. data/spec/{bson/corpus_spec.rb → spec_tests/corpus_legacy_spec.rb} +4 -4
  94. data/spec/spec_tests/corpus_spec.rb +124 -0
  95. data/spec/spec_tests/data/corpus/README.md +15 -0
  96. data/spec/spec_tests/data/corpus/array.json +49 -0
  97. data/spec/spec_tests/data/corpus/binary.json +85 -0
  98. data/spec/spec_tests/data/corpus/boolean.json +27 -0
  99. data/spec/spec_tests/data/corpus/code.json +67 -0
  100. data/spec/spec_tests/data/corpus/code_w_scope.json +78 -0
  101. data/spec/spec_tests/data/corpus/datetime.json +42 -0
  102. data/spec/spec_tests/data/corpus/dbpointer.json +56 -0
  103. data/spec/spec_tests/data/corpus/dbref.json +31 -0
  104. data/spec/spec_tests/data/corpus/decimal128-1.json +317 -0
  105. data/spec/spec_tests/data/corpus/decimal128-2.json +793 -0
  106. data/spec/spec_tests/data/corpus/decimal128-3.json +1771 -0
  107. data/spec/spec_tests/data/corpus/decimal128-4.json +117 -0
  108. data/spec/spec_tests/data/corpus/decimal128-5.json +402 -0
  109. data/spec/spec_tests/data/corpus/decimal128-6.json +119 -0
  110. data/spec/spec_tests/data/corpus/decimal128-7.json +323 -0
  111. data/spec/spec_tests/data/corpus/document.json +36 -0
  112. data/spec/spec_tests/data/corpus/double.json +87 -0
  113. data/spec/spec_tests/data/corpus/int32.json +43 -0
  114. data/spec/spec_tests/data/corpus/int64.json +43 -0
  115. data/spec/spec_tests/data/corpus/maxkey.json +12 -0
  116. data/spec/spec_tests/data/corpus/minkey.json +12 -0
  117. data/spec/spec_tests/data/corpus/multi-type-deprecated.json +15 -0
  118. data/spec/spec_tests/data/corpus/multi-type.json +11 -0
  119. data/spec/spec_tests/data/corpus/null.json +12 -0
  120. data/spec/spec_tests/data/corpus/oid.json +28 -0
  121. data/spec/spec_tests/data/corpus/regex.json +65 -0
  122. data/spec/spec_tests/data/corpus/string.json +72 -0
  123. data/spec/spec_tests/data/corpus/symbol.json +80 -0
  124. data/spec/spec_tests/data/corpus/timestamp.json +24 -0
  125. data/spec/spec_tests/data/corpus/top.json +236 -0
  126. data/spec/spec_tests/data/corpus/undefined.json +15 -0
  127. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/array.json +0 -0
  128. data/spec/{support/corpus-tests/failures → spec_tests/data/corpus_legacy}/binary.json +0 -0
  129. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/boolean.json +0 -0
  130. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/code.json +1 -1
  131. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/code_w_scope.json +1 -1
  132. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/document.json +1 -1
  133. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/double.json +1 -1
  134. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/failures/datetime.json +0 -0
  135. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/failures/dbpointer.json +0 -0
  136. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/failures/int64.json +0 -0
  137. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/failures/symbol.json +0 -0
  138. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/int32.json +1 -1
  139. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/maxkey.json +1 -1
  140. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/minkey.json +1 -1
  141. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/null.json +1 -1
  142. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/oid.json +0 -0
  143. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/regex.json +1 -1
  144. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/string.json +0 -0
  145. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/timestamp.json +1 -1
  146. data/spec/{support/corpus-tests → spec_tests/data/corpus_legacy}/top.json +0 -0
  147. data/spec/{support/corpus-tests/failures → spec_tests/data/corpus_legacy}/undefined.json +0 -0
  148. data/spec/{support/driver-spec-tests → spec_tests/data}/decimal128/decimal128-1.json +0 -0
  149. data/spec/{support/driver-spec-tests → spec_tests/data}/decimal128/decimal128-2.json +0 -0
  150. data/spec/{support/driver-spec-tests → spec_tests/data}/decimal128/decimal128-3.json +0 -0
  151. data/spec/{support/driver-spec-tests → spec_tests/data}/decimal128/decimal128-4.json +0 -0
  152. data/spec/{support/driver-spec-tests → spec_tests/data}/decimal128/decimal128-5.json +0 -0
  153. data/spec/{support/driver-spec-tests → spec_tests/data}/decimal128/decimal128-6.json +0 -0
  154. data/spec/{support/driver-spec-tests → spec_tests/data}/decimal128/decimal128-7.json +0 -0
  155. data/spec/support/shared_examples.rb +1 -1
  156. metadata +172 -120
  157. checksums.yaml.gz.sig +0 -0
  158. data.tar.gz.sig +0 -1
  159. metadata.gz.sig +0 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ac48ca5a022cc024d0ced56d11165c4a54d01610c1e805634510ad52db11cd7a
4
- data.tar.gz: 8440d253b13a60d3af1f3e9b2179e8c376ecae89a3ea4a6cb7a3263f32d14e06
3
+ metadata.gz: 05c17fcaee2ceaefe97d801594460178acaf6a2f82c152ce33db819f01d624fa
4
+ data.tar.gz: 3343dfda6f4038fa261d077ddf860dd43ff001d2fbea7189110b6fa500fb2558
5
5
  SHA512:
6
- metadata.gz: 8ffde24e9e88fd73f5e1a847c3494449ed1973348fd8407846f1a18a7671eff32ebc5df921a33fbbe0e978ed014b1bd49f93d32fb6ca213ef4bd287a2991439d
7
- data.tar.gz: 1356bf7ffc9bdf12f96aa5efd32e5562eeabe1e13191354f2658f826c215833b3af30d65367c6316c955db98675ad8ee5c79ca0ec06793456fe2effd9a5700d2
6
+ metadata.gz: 7756cee7923f3ca584e6a1bfa3666f70d2f14804b3ddb913f0695be3495a061a632803a90d1cd87a63c95d5b9222c02b18fe475a38e2a8a680914819f90f4471
7
+ data.tar.gz: 88bf0b45ecbe2aa47c955ca5281568cbe6d48a4c144a5b49680f6f7d8684fa61524dcc80474118c12e9df13b6bfc4ffca1a0d0e55679c0325dcdfd48543aab96
data/README.md CHANGED
@@ -1,4 +1,8 @@
1
- BSON [![Build Status](https://secure.travis-ci.org/mongodb/bson-ruby.png?branch=master&.png)](http://travis-ci.org/mongodb/bson-ruby) [![Code Climate](https://codeclimate.com/github/mongodb/bson-ruby.png)](https://codeclimate.com/github/mongodb/bson-ruby) [![Coverage Status](https://coveralls.io/repos/mongodb/bson-ruby/badge.png?branch=master)](https://coveralls.io/r/mongodb/bson-ruby?branch=master) [![Inline docs](http://inch-ci.org/github/mongodb/bson-ruby.svg?branch=master)](http://inch-ci.org/github/mongodb/bson-ruby)
1
+ BSON [![Build Status](https://secure.travis-ci.org/mongodb/bson-ruby.svg?branch=master)](http://travis-ci.org/mongodb/bson-ruby)
2
+ [![Build status Windows](https://ci.appveyor.com/api/projects/status/p5aqko7umsx351nm?svg=true)](https://ci.appveyor.com/project/p-mongo/bson-ruby/branch/master)
3
+ [![Code Climate](https://codeclimate.com/github/mongodb/bson-ruby.svg)](https://codeclimate.com/github/mongodb/bson-ruby)
4
+ [![Coverage Status](https://coveralls.io/repos/mongodb/bson-ruby/badge.svg?branch=master)](https://coveralls.io/r/mongodb/bson-ruby?branch=master)
5
+ [![Inline docs](http://inch-ci.org/github/mongodb/bson-ruby.svg?branch=master)](http://inch-ci.org/github/mongodb/bson-ruby)
2
6
  ====
3
7
 
4
8
  An implementation of the BSON specification in Ruby.
@@ -34,7 +38,7 @@ As of 2.0.0, this project adheres to the
34
38
  License
35
39
  -------
36
40
 
37
- Copyright (C) 2009-2019 MongoDB Inc.
41
+ Copyright (C) 2009-2020 MongoDB Inc.
38
42
 
39
43
  Licensed under the Apache License, Version 2.0 (the "License");
40
44
  you may not use this file except in compliance with the License.
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (C) 2015-2019 MongoDB, Inc.
2
+ * Copyright (C) 2015-2020 MongoDB Inc.
3
3
  *
4
4
  * Licensed under the Apache License, Version 2.0 (the "License");
5
5
  * you may not use this file except in compliance with the License.
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (C) 2009-2019 MongoDB, Inc.
2
+ * Copyright (C) 2009-2020 MongoDB Inc.
3
3
  *
4
4
  * Licensed under the Apache License, Version 2.0 (the "License");
5
5
  * you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
16
16
 
17
17
  #include <ruby.h>
18
18
  #include <stdbool.h>
19
+ #include <stdint.h>
19
20
  #include <unistd.h>
20
21
  #include <time.h>
21
22
  #include "bson-endian.h"
@@ -32,13 +33,15 @@ rb_bson_utf8_validate (const char *utf8, /* IN */
32
33
  #define HOST_NAME_HASH_MAX 256
33
34
  #endif
34
35
 
36
+ /* See the type list in http://bsonspec.org/spec.html. */
35
37
  #define BSON_TYPE_DOUBLE 1
36
38
  #define BSON_TYPE_STRING 2
37
39
  #define BSON_TYPE_DOCUMENT 3
38
40
  #define BSON_TYPE_ARRAY 4
39
41
  #define BSON_TYPE_BOOLEAN 8
40
- #define BSON_TYPE_INT32 16
41
- #define BSON_TYPE_INT64 18
42
+ #define BSON_TYPE_SYMBOL 0x0E
43
+ #define BSON_TYPE_INT32 0x10
44
+ #define BSON_TYPE_INT64 0x12
42
45
 
43
46
  typedef struct {
44
47
  size_t size;
@@ -75,8 +78,8 @@ VALUE rb_bson_byte_buffer_get_double(VALUE self);
75
78
  VALUE rb_bson_byte_buffer_get_int32(VALUE self);
76
79
  VALUE rb_bson_byte_buffer_get_int64(VALUE self);
77
80
  VALUE rb_bson_byte_buffer_get_string(VALUE self);
78
- VALUE rb_bson_byte_buffer_get_hash(VALUE self);
79
- VALUE rb_bson_byte_buffer_get_array(VALUE self);
81
+ VALUE rb_bson_byte_buffer_get_hash(int argc, VALUE *argv, VALUE self);
82
+ VALUE rb_bson_byte_buffer_get_array(int argc, VALUE *argv, VALUE self);
80
83
  VALUE rb_bson_byte_buffer_put_byte(VALUE self, VALUE byte);
81
84
  VALUE rb_bson_byte_buffer_put_bytes(VALUE self, VALUE bytes);
82
85
  VALUE rb_bson_byte_buffer_put_cstring(VALUE self, VALUE string);
@@ -100,6 +103,14 @@ void rb_bson_byte_buffer_free(void *ptr);
100
103
  void rb_bson_expand_buffer(byte_buffer_t* buffer_ptr, size_t length);
101
104
  void rb_bson_generate_machine_id(VALUE rb_md5_class, char *rb_bson_machine_id);
102
105
 
106
+ VALUE pvt_const_get_2(const char *c1, const char *c2);
107
+ VALUE pvt_const_get_3(const char *c1, const char *c2, const char *c3);
108
+
109
+ #define BSON_MODE_DEFAULT 0
110
+ #define BSON_MODE_BSON 1
111
+
112
+ int pvt_get_mode_option(int argc, VALUE *argv);
113
+
103
114
  /**
104
115
  * The counter for incrementing object ids.
105
116
  */
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (C) 2009-2019 MongoDB, Inc.
2
+ * Copyright (C) 2009-2020 MongoDB Inc.
3
3
  *
4
4
  * Licensed under the Apache License, Version 2.0 (the "License");
5
5
  * you may not use this file except in compliance with the License.
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (C) 2015-2019 MongoDB, Inc.
2
+ * Copyright (C) 2015-2020 MongoDB Inc.
3
3
  *
4
4
  * Licensed under the Apache License, Version 2.0 (the "License");
5
5
  * you may not use this file except in compliance with the License.
@@ -15,6 +15,7 @@
15
15
  */
16
16
 
17
17
  #include <string.h>
18
+ #include <stdint.h>
18
19
  #include "bson-endian.h"
19
20
 
20
21
  /*
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (C) 2009-2019 MongoDB Inc.
2
+ * Copyright (C) 2009-2020 MongoDB Inc.
3
3
  *
4
4
  * Licensed under the Apache License, Version 2.0 (the "License");
5
5
  * you may not use this file except in compliance with the License.
@@ -70,8 +70,31 @@ void Init_bson_native()
70
70
  rb_define_method(rb_byte_buffer_class, "get_cstring", rb_bson_byte_buffer_get_cstring, 0);
71
71
  rb_define_method(rb_byte_buffer_class, "get_decimal128_bytes", rb_bson_byte_buffer_get_decimal128_bytes, 0);
72
72
  rb_define_method(rb_byte_buffer_class, "get_double", rb_bson_byte_buffer_get_double, 0);
73
- rb_define_method(rb_byte_buffer_class, "get_hash", rb_bson_byte_buffer_get_hash, 0);
74
- rb_define_method(rb_byte_buffer_class, "get_array", rb_bson_byte_buffer_get_array, 0);
73
+
74
+ /*
75
+ * call-seq:
76
+ * buffer.get_hash(**options) -> Hash
77
+ *
78
+ * Reads a document from the byte buffer and returns it as a BSON::Document.
79
+ *
80
+ * @option options [ nil | :bson ] :mode Decoding mode to use.
81
+ *
82
+ * @return [ BSON::Document ] The decoded document.
83
+ */
84
+ rb_define_method(rb_byte_buffer_class, "get_hash", rb_bson_byte_buffer_get_hash, -1);
85
+
86
+ /*
87
+ * call-seq:
88
+ * buffer.get_array(**options) -> Array
89
+ *
90
+ * Reads an array from the byte buffer..
91
+ *
92
+ * @option options [ nil | :bson ] :mode Decoding mode to use.
93
+ *
94
+ * @return [ Array ] The decoded array.
95
+ */
96
+ rb_define_method(rb_byte_buffer_class, "get_array", rb_bson_byte_buffer_get_array, -1);
97
+
75
98
  rb_define_method(rb_byte_buffer_class, "get_int32", rb_bson_byte_buffer_get_int32, 0);
76
99
  rb_define_method(rb_byte_buffer_class, "get_int64", rb_bson_byte_buffer_get_int64, 0);
77
100
  rb_define_method(rb_byte_buffer_class, "get_string", rb_bson_byte_buffer_get_string, 0);
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (C) 2009-2019 MongoDB, Inc.
2
+ * Copyright (C) 2009-2020 MongoDB Inc.
3
3
  *
4
4
  * Licensed under the Apache License, Version 2.0 (the "License");
5
5
  * you may not use this file except in compliance with the License.
@@ -17,21 +17,28 @@
17
17
  #include "bson-native.h"
18
18
  #include <ruby/encoding.h>
19
19
 
20
- static void pvt_validate_length(byte_buffer_t *b);
20
+ static void pvt_raise_decode_error(volatile VALUE msg);
21
+ static int32_t pvt_validate_length(byte_buffer_t *b);
21
22
  static uint8_t pvt_get_type_byte(byte_buffer_t *b);
22
23
  static VALUE pvt_get_int32(byte_buffer_t *b);
23
- static VALUE pvt_get_int64(byte_buffer_t *b);
24
+ static VALUE pvt_get_int64(byte_buffer_t *b, int argc, VALUE *argv);
24
25
  static VALUE pvt_get_double(byte_buffer_t *b);
25
- static VALUE pvt_get_string(byte_buffer_t *b);
26
+ static VALUE pvt_get_string(byte_buffer_t *b, const char *data_type);
27
+ static VALUE pvt_get_symbol(byte_buffer_t *b, VALUE rb_buffer, int argc, VALUE *argv);
26
28
  static VALUE pvt_get_boolean(byte_buffer_t *b);
27
- static VALUE pvt_read_field(byte_buffer_t *b, VALUE rb_buffer, uint8_t type);
29
+ static VALUE pvt_read_field(byte_buffer_t *b, VALUE rb_buffer, uint8_t type, int argc, VALUE *argv);
28
30
  static void pvt_skip_cstring(byte_buffer_t *b);
29
31
 
32
+ void pvt_raise_decode_error(volatile VALUE msg) {
33
+ VALUE klass = pvt_const_get_3("BSON", "Error", "BSONDecodeError");
34
+ rb_exc_raise(rb_exc_new_str(klass, msg));
35
+ }
36
+
30
37
  /**
31
38
  * validate the buffer contains the amount of bytes the array / hash claimns
32
39
  * and that it is null terminated
33
40
  */
34
- void pvt_validate_length(byte_buffer_t *b)
41
+ int32_t pvt_validate_length(byte_buffer_t *b)
35
42
  {
36
43
  int32_t length;
37
44
 
@@ -52,19 +59,23 @@ void pvt_validate_length(byte_buffer_t *b)
52
59
  else{
53
60
  rb_raise(rb_eRangeError, "Buffer contained invalid length %d at %zu", length, b->read_position);
54
61
  }
62
+
63
+ return length;
55
64
  }
56
65
 
57
66
  /**
58
67
  * Read a single field from a hash or array
59
68
  */
60
- VALUE pvt_read_field(byte_buffer_t *b, VALUE rb_buffer, uint8_t type){
69
+ VALUE pvt_read_field(byte_buffer_t *b, VALUE rb_buffer, uint8_t type, int argc, VALUE *argv)
70
+ {
61
71
  switch(type) {
62
72
  case BSON_TYPE_INT32: return pvt_get_int32(b);
63
- case BSON_TYPE_INT64: return pvt_get_int64(b);
73
+ case BSON_TYPE_INT64: return pvt_get_int64(b, argc, argv);
64
74
  case BSON_TYPE_DOUBLE: return pvt_get_double(b);
65
- case BSON_TYPE_STRING: return pvt_get_string(b);
66
- case BSON_TYPE_ARRAY: return rb_bson_byte_buffer_get_array(rb_buffer);
67
- case BSON_TYPE_DOCUMENT: return rb_bson_byte_buffer_get_hash(rb_buffer);
75
+ case BSON_TYPE_STRING: return pvt_get_string(b, "String");
76
+ case BSON_TYPE_SYMBOL: return pvt_get_symbol(b, rb_buffer, argc, argv);
77
+ case BSON_TYPE_ARRAY: return rb_bson_byte_buffer_get_array(argc, argv, rb_buffer);
78
+ case BSON_TYPE_DOCUMENT: return rb_bson_byte_buffer_get_hash(argc, argv, rb_buffer);
68
79
  case BSON_TYPE_BOOLEAN: return pvt_get_boolean(b);
69
80
  default:
70
81
  {
@@ -116,9 +127,20 @@ VALUE rb_bson_byte_buffer_get_bytes(VALUE self, VALUE i)
116
127
  }
117
128
 
118
129
  VALUE pvt_get_boolean(byte_buffer_t *b){
119
- VALUE result = Qnil;
130
+ VALUE result;
131
+ char byte_value;
120
132
  ENSURE_BSON_READ(b, 1);
121
- result = *READ_PTR(b) == 1 ? Qtrue: Qfalse;
133
+ byte_value = *READ_PTR(b);
134
+ switch (byte_value) {
135
+ case 1:
136
+ result = Qtrue;
137
+ break;
138
+ case 0:
139
+ result = Qfalse;
140
+ break;
141
+ default:
142
+ pvt_raise_decode_error(rb_sprintf("Invalid boolean byte value: %d", (int) byte_value));
143
+ }
122
144
  b->read_position += 1;
123
145
  return result;
124
146
  }
@@ -131,25 +153,63 @@ VALUE rb_bson_byte_buffer_get_string(VALUE self)
131
153
  byte_buffer_t *b;
132
154
 
133
155
  TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b);
134
- return pvt_get_string(b);
156
+ return pvt_get_string(b, "String");
135
157
  }
136
158
 
137
- VALUE pvt_get_string(byte_buffer_t *b)
159
+ VALUE pvt_get_string(byte_buffer_t *b, const char *data_type)
138
160
  {
139
- int32_t length;
140
161
  int32_t length_le;
162
+ int32_t length;
163
+ char *str_ptr;
141
164
  VALUE string;
165
+ unsigned char last_byte;
142
166
 
143
167
  ENSURE_BSON_READ(b, 4);
144
- memcpy(&length, READ_PTR(b), 4);
145
- length_le = BSON_UINT32_FROM_LE(length);
146
- b->read_position += 4;
147
- ENSURE_BSON_READ(b, length_le);
148
- string = rb_enc_str_new(READ_PTR(b), length_le - 1, rb_utf8_encoding());
149
- b->read_position += length_le;
168
+ memcpy(&length_le, READ_PTR(b), 4);
169
+ length = BSON_UINT32_FROM_LE(length_le);
170
+ if (length < 0) {
171
+ pvt_raise_decode_error(rb_sprintf("String length is negative: %d", length));
172
+ }
173
+ if (length == 0) {
174
+ pvt_raise_decode_error(rb_str_new_cstr("String length is zero but string must be null-terminated"));
175
+ }
176
+ ENSURE_BSON_READ(b, 4 + length);
177
+ str_ptr = READ_PTR(b) + 4;
178
+ last_byte = *(READ_PTR(b) + 4 + length_le - 1);
179
+ if (last_byte != 0) {
180
+ pvt_raise_decode_error(rb_sprintf("Last byte of the string is not null: 0x%x", (int) last_byte));
181
+ }
182
+ rb_bson_utf8_validate(str_ptr, length - 1, true, data_type);
183
+ string = rb_enc_str_new(str_ptr, length - 1, rb_utf8_encoding());
184
+ b->read_position += 4 + length_le;
150
185
  return string;
151
186
  }
152
187
 
188
+ /**
189
+ * Reads a UTF-8 string out of the byte buffer. If the argc/argv arguments
190
+ * have a :mode option with the value of :bson, wraps the string in a
191
+ * BSON::Symbol::Raw. Otherwise consults the BSON registry to determine
192
+ * which class to instantiate (String in bson-ruby, overridden to Symbol by
193
+ * the Ruby driver). Returns either a BSON::Symbol::Raw, Symbol or String
194
+ * value.
195
+ */
196
+ VALUE pvt_get_symbol(byte_buffer_t *b, VALUE rb_buffer, int argc, VALUE *argv)
197
+ {
198
+ VALUE value, klass;
199
+
200
+ if (pvt_get_mode_option(argc, argv) == BSON_MODE_BSON) {
201
+ value = pvt_get_string(b, "Symbol");
202
+ klass = pvt_const_get_3("BSON", "Symbol", "Raw");
203
+ value = rb_funcall(klass, rb_intern("new"), 1, value);
204
+ } else {
205
+ klass = rb_funcall(rb_bson_registry, rb_intern("get"), 1, INT2FIX(BSON_TYPE_SYMBOL));
206
+ value = rb_funcall(klass, rb_intern("from_bson"), 1, rb_buffer);
207
+ }
208
+
209
+ RB_GC_GUARD(klass);
210
+ return value;
211
+ }
212
+
153
213
  /**
154
214
  * Get a cstring from the buffer.
155
215
  */
@@ -206,17 +266,35 @@ VALUE rb_bson_byte_buffer_get_int64(VALUE self)
206
266
  {
207
267
  byte_buffer_t *b;
208
268
  TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b);
209
- return pvt_get_int64(b);
269
+ return pvt_get_int64(b, 0, NULL);
210
270
  }
211
271
 
212
- VALUE pvt_get_int64(byte_buffer_t *b)
272
+ /**
273
+ * Reads a 64-bit integer out of the byte buffer into a Ruby Integer instance.
274
+ * If the argc/argv arguments have a :mode option with the value of :bson,
275
+ * wraps the integer in a BSON::Int64. Returns either the Integer or the
276
+ * BSON::Int64 instance.
277
+ */
278
+ VALUE pvt_get_int64(byte_buffer_t *b, int argc, VALUE *argv)
213
279
  {
214
280
  int64_t i64;
281
+ VALUE num;
215
282
 
216
283
  ENSURE_BSON_READ(b, 8);
217
284
  memcpy(&i64, READ_PTR(b), 8);
218
285
  b->read_position += 8;
219
- return LL2NUM(BSON_UINT64_FROM_LE(i64));
286
+ num = LL2NUM(BSON_UINT64_FROM_LE(i64));
287
+
288
+ if (pvt_get_mode_option(argc, argv) == BSON_MODE_BSON) {
289
+ VALUE klass = rb_funcall(rb_bson_registry,rb_intern("get"),1, INT2FIX(BSON_TYPE_INT64));
290
+ VALUE value = rb_funcall(klass, rb_intern("new"), 1, num);
291
+ RB_GC_GUARD(klass);
292
+ return value;
293
+ } else {
294
+ return num;
295
+ }
296
+
297
+ RB_GC_GUARD(num);
220
298
  }
221
299
 
222
300
  /**
@@ -255,40 +333,56 @@ VALUE rb_bson_byte_buffer_get_decimal128_bytes(VALUE self)
255
333
  return bytes;
256
334
  }
257
335
 
258
- VALUE rb_bson_byte_buffer_get_hash(VALUE self){
336
+ VALUE rb_bson_byte_buffer_get_hash(int argc, VALUE *argv, VALUE self){
259
337
  VALUE doc = Qnil;
260
338
  byte_buffer_t *b = NULL;
261
339
  uint8_t type;
262
- VALUE cDocument = rb_const_get(rb_const_get(rb_cObject, rb_intern("BSON")), rb_intern("Document"));
340
+ VALUE cDocument = pvt_const_get_2("BSON", "Document");
341
+ int32_t length;
342
+ char *start_ptr;
263
343
 
264
344
  TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b);
265
345
 
266
- pvt_validate_length(b);
346
+ start_ptr = READ_PTR(b);
347
+ length = pvt_validate_length(b);
267
348
 
268
- doc = rb_funcall(cDocument, rb_intern("allocate"),0);
349
+ doc = rb_funcall(cDocument, rb_intern("allocate"), 0);
269
350
 
270
351
  while((type = pvt_get_type_byte(b)) != 0){
271
352
  VALUE field = rb_bson_byte_buffer_get_cstring(self);
353
+ rb_hash_aset(doc, field, pvt_read_field(b, self, type, argc, argv));
272
354
  RB_GC_GUARD(field);
273
- rb_hash_aset(doc, field, pvt_read_field(b, self, type));
274
355
  }
356
+
357
+ if (READ_PTR(b) - start_ptr != length) {
358
+ pvt_raise_decode_error(rb_sprintf("Expected to read %d bytes for the hash but read %ld bytes", length, READ_PTR(b) - start_ptr));
359
+ }
360
+
275
361
  return doc;
276
362
  }
277
363
 
278
- VALUE rb_bson_byte_buffer_get_array(VALUE self){
364
+ VALUE rb_bson_byte_buffer_get_array(int argc, VALUE *argv, VALUE self){
279
365
  byte_buffer_t *b;
280
366
  VALUE array = Qnil;
281
367
  uint8_t type;
368
+ int32_t length;
369
+ char *start_ptr;
282
370
 
283
371
  TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b);
284
372
 
285
- pvt_validate_length(b);
373
+ start_ptr = READ_PTR(b);
374
+ length = pvt_validate_length(b);
286
375
 
287
376
  array = rb_ary_new();
288
377
  while((type = pvt_get_type_byte(b)) != 0){
289
378
  pvt_skip_cstring(b);
290
- rb_ary_push(array, pvt_read_field(b, self, type));
379
+ rb_ary_push(array, pvt_read_field(b, self, type, argc, argv));
291
380
  }
292
381
  RB_GC_GUARD(array);
382
+
383
+ if (READ_PTR(b) - start_ptr != length) {
384
+ pvt_raise_decode_error(rb_sprintf("Expected to read %d bytes for the hash but read %ld bytes", length, READ_PTR(b) - start_ptr));
385
+ }
386
+
293
387
  return array;
294
388
  }
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (C) 2009-2019 MongoDB, Inc.
2
+ * Copyright (C) 2009-2020 MongoDB Inc.
3
3
  *
4
4
  * Licensed under the Apache License, Version 2.0 (the "License");
5
5
  * you may not use this file except in compliance with the License.
@@ -53,3 +53,43 @@ VALUE rb_bson_object_id_generator_next(int argc, VALUE* args, VALUE self)
53
53
  rb_bson_object_id_counter++;
54
54
  return rb_str_new(bytes, 12);
55
55
  }
56
+
57
+ /**
58
+ * Returns a Ruby constant nested one level, e.g. BSON::Document.
59
+ */
60
+ VALUE pvt_const_get_2(const char *c1, const char *c2) {
61
+ return rb_const_get(rb_const_get(rb_cObject, rb_intern(c1)), rb_intern(c2));
62
+ }
63
+
64
+ /**
65
+ * Returns a Ruby constant nested two levels, e.g. BSON::Regexp::Raw.
66
+ */
67
+ VALUE pvt_const_get_3(const char *c1, const char *c2, const char *c3) {
68
+ return rb_const_get(pvt_const_get_2(c1, c2), rb_intern(c3));
69
+ }
70
+
71
+ /**
72
+ * Returns the value of the :mode option, or the default if the option is not
73
+ * specified. Raises ArgumentError if the value is not one of nil or :bson.
74
+ * A future version of bson-ruby is expected to also support :ruby and :ruby!
75
+ * values. Returns one of the BSON_MODE_* values.
76
+ */
77
+ int pvt_get_mode_option(int argc, VALUE *argv) {
78
+ VALUE opts;
79
+ VALUE mode;
80
+
81
+ rb_scan_args(argc, argv, ":", &opts);
82
+ if (NIL_P(opts)) {
83
+ return BSON_MODE_DEFAULT;
84
+ } else {
85
+ mode = rb_hash_lookup(opts, ID2SYM(rb_intern("mode")));
86
+ if (mode == Qnil) {
87
+ return BSON_MODE_DEFAULT;
88
+ } else if (mode == ID2SYM(rb_intern("bson"))) {
89
+ return BSON_MODE_BSON;
90
+ } else {
91
+ rb_raise(rb_eArgError, "Invalid value for :mode option: %s",
92
+ RSTRING_PTR(rb_funcall(mode, rb_intern("inspect"), 0)));
93
+ }
94
+ }
95
+ }