bson 4.5.0 → 4.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,294 @@
1
+ /*
2
+ * Copyright (C) 2009-2019 MongoDB, Inc.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ #include "bson-native.h"
18
+ #include <ruby/encoding.h>
19
+
20
+ static void pvt_validate_length(byte_buffer_t *b);
21
+ static uint8_t pvt_get_type_byte(byte_buffer_t *b);
22
+ static VALUE pvt_get_int32(byte_buffer_t *b);
23
+ static VALUE pvt_get_int64(byte_buffer_t *b);
24
+ static VALUE pvt_get_double(byte_buffer_t *b);
25
+ static VALUE pvt_get_string(byte_buffer_t *b);
26
+ 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);
28
+ static void pvt_skip_cstring(byte_buffer_t *b);
29
+
30
+ /**
31
+ * validate the buffer contains the amount of bytes the array / hash claimns
32
+ * and that it is null terminated
33
+ */
34
+ void pvt_validate_length(byte_buffer_t *b)
35
+ {
36
+ int32_t length;
37
+
38
+ ENSURE_BSON_READ(b, 4);
39
+ memcpy(&length, READ_PTR(b), 4);
40
+ length = BSON_UINT32_TO_LE(length);
41
+
42
+ /* minimum valid length is 4 (byte count) + 1 (terminating byte) */
43
+ if(length >= 5){
44
+ ENSURE_BSON_READ(b, length);
45
+
46
+ /* The last byte should be a null byte: it should be at length - 1 */
47
+ if( *(READ_PTR(b) + length - 1) != 0 ){
48
+ rb_raise(rb_eRangeError, "Buffer should have contained null terminator at %zu but contained %d", b->read_position + (size_t)length, (int)*(READ_PTR(b) + length));
49
+ }
50
+ b->read_position += 4;
51
+ }
52
+ else{
53
+ rb_raise(rb_eRangeError, "Buffer contained invalid length %d at %zu", length, b->read_position);
54
+ }
55
+ }
56
+
57
+ /**
58
+ * Read a single field from a hash or array
59
+ */
60
+ VALUE pvt_read_field(byte_buffer_t *b, VALUE rb_buffer, uint8_t type){
61
+ switch(type) {
62
+ case BSON_TYPE_INT32: return pvt_get_int32(b);
63
+ case BSON_TYPE_INT64: return pvt_get_int64(b);
64
+ 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);
68
+ case BSON_TYPE_BOOLEAN: return pvt_get_boolean(b);
69
+ default:
70
+ {
71
+ VALUE klass = rb_funcall(rb_bson_registry,rb_intern("get"),1, INT2FIX(type));
72
+ VALUE value = rb_funcall(klass, rb_intern("from_bson"),1, rb_buffer);
73
+ RB_GC_GUARD(klass);
74
+ return value;
75
+ }
76
+ }
77
+ }
78
+
79
+ /**
80
+ * Get a single byte from the buffer.
81
+ */
82
+ VALUE rb_bson_byte_buffer_get_byte(VALUE self)
83
+ {
84
+ byte_buffer_t *b;
85
+ VALUE byte;
86
+
87
+ TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b);
88
+ ENSURE_BSON_READ(b, 1);
89
+ byte = rb_str_new(READ_PTR(b), 1);
90
+ b->read_position += 1;
91
+ return byte;
92
+ }
93
+
94
+ uint8_t pvt_get_type_byte(byte_buffer_t *b){
95
+ int8_t byte;
96
+ ENSURE_BSON_READ(b, 1);
97
+ byte = *READ_PTR(b);
98
+ b->read_position += 1;
99
+ return (uint8_t)byte;
100
+ }
101
+
102
+ /**
103
+ * Get bytes from the buffer.
104
+ */
105
+ VALUE rb_bson_byte_buffer_get_bytes(VALUE self, VALUE i)
106
+ {
107
+ byte_buffer_t *b;
108
+ VALUE bytes;
109
+ const uint32_t length = FIX2LONG(i);
110
+
111
+ TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b);
112
+ ENSURE_BSON_READ(b, length);
113
+ bytes = rb_str_new(READ_PTR(b), length);
114
+ b->read_position += length;
115
+ return bytes;
116
+ }
117
+
118
+ VALUE pvt_get_boolean(byte_buffer_t *b){
119
+ VALUE result = Qnil;
120
+ ENSURE_BSON_READ(b, 1);
121
+ result = *READ_PTR(b) == 1 ? Qtrue: Qfalse;
122
+ b->read_position += 1;
123
+ return result;
124
+ }
125
+
126
+ /**
127
+ * Get a string from the buffer.
128
+ */
129
+ VALUE rb_bson_byte_buffer_get_string(VALUE self)
130
+ {
131
+ byte_buffer_t *b;
132
+
133
+ TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b);
134
+ return pvt_get_string(b);
135
+ }
136
+
137
+ VALUE pvt_get_string(byte_buffer_t *b)
138
+ {
139
+ int32_t length;
140
+ int32_t length_le;
141
+ VALUE string;
142
+
143
+ 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;
150
+ return string;
151
+ }
152
+
153
+ /**
154
+ * Get a cstring from the buffer.
155
+ */
156
+ VALUE rb_bson_byte_buffer_get_cstring(VALUE self)
157
+ {
158
+ byte_buffer_t *b;
159
+ VALUE string;
160
+ int length;
161
+
162
+ TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b);
163
+ length = (int)strlen(READ_PTR(b));
164
+ ENSURE_BSON_READ(b, length);
165
+ string = rb_enc_str_new(READ_PTR(b), length, rb_utf8_encoding());
166
+ b->read_position += length + 1;
167
+ return string;
168
+ }
169
+
170
+ /**
171
+ * Reads but does not return a cstring from the buffer.
172
+ */
173
+ void pvt_skip_cstring(byte_buffer_t *b)
174
+ {
175
+ int length;
176
+ length = (int)strlen(READ_PTR(b));
177
+ ENSURE_BSON_READ(b, length);
178
+ b->read_position += length + 1;
179
+ }
180
+
181
+ /**
182
+ * Get a int32 from the buffer.
183
+ */
184
+ VALUE rb_bson_byte_buffer_get_int32(VALUE self)
185
+ {
186
+ byte_buffer_t *b;
187
+
188
+ TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b);
189
+ return pvt_get_int32(b);
190
+ }
191
+
192
+ VALUE pvt_get_int32(byte_buffer_t *b)
193
+ {
194
+ int32_t i32;
195
+
196
+ ENSURE_BSON_READ(b, 4);
197
+ memcpy(&i32, READ_PTR(b), 4);
198
+ b->read_position += 4;
199
+ return INT2NUM(BSON_UINT32_FROM_LE(i32));
200
+ }
201
+
202
+ /**
203
+ * Get a int64 from the buffer.
204
+ */
205
+ VALUE rb_bson_byte_buffer_get_int64(VALUE self)
206
+ {
207
+ byte_buffer_t *b;
208
+ TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b);
209
+ return pvt_get_int64(b);
210
+ }
211
+
212
+ VALUE pvt_get_int64(byte_buffer_t *b)
213
+ {
214
+ int64_t i64;
215
+
216
+ ENSURE_BSON_READ(b, 8);
217
+ memcpy(&i64, READ_PTR(b), 8);
218
+ b->read_position += 8;
219
+ return LL2NUM(BSON_UINT64_FROM_LE(i64));
220
+ }
221
+
222
+ /**
223
+ * Get a double from the buffer.
224
+ */
225
+ VALUE rb_bson_byte_buffer_get_double(VALUE self)
226
+ {
227
+ byte_buffer_t *b;
228
+
229
+ TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b);
230
+ return pvt_get_double(b);
231
+ }
232
+
233
+ VALUE pvt_get_double(byte_buffer_t *b)
234
+ {
235
+ double d;
236
+
237
+ ENSURE_BSON_READ(b, 8);
238
+ memcpy(&d, READ_PTR(b), 8);
239
+ b->read_position += 8;
240
+ return DBL2NUM(BSON_DOUBLE_FROM_LE(d));
241
+ }
242
+
243
+ /**
244
+ * Get the 16 bytes representing the decimal128 from the buffer.
245
+ */
246
+ VALUE rb_bson_byte_buffer_get_decimal128_bytes(VALUE self)
247
+ {
248
+ byte_buffer_t *b;
249
+ VALUE bytes;
250
+
251
+ TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b);
252
+ ENSURE_BSON_READ(b, 16);
253
+ bytes = rb_str_new(READ_PTR(b), 16);
254
+ b->read_position += 16;
255
+ return bytes;
256
+ }
257
+
258
+ VALUE rb_bson_byte_buffer_get_hash(VALUE self){
259
+ VALUE doc = Qnil;
260
+ byte_buffer_t *b = NULL;
261
+ uint8_t type;
262
+ VALUE cDocument = rb_const_get(rb_const_get(rb_cObject, rb_intern("BSON")), rb_intern("Document"));
263
+
264
+ TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b);
265
+
266
+ pvt_validate_length(b);
267
+
268
+ doc = rb_funcall(cDocument, rb_intern("allocate"),0);
269
+
270
+ while((type = pvt_get_type_byte(b)) != 0){
271
+ VALUE field = rb_bson_byte_buffer_get_cstring(self);
272
+ RB_GC_GUARD(field);
273
+ rb_hash_aset(doc, field, pvt_read_field(b, self, type));
274
+ }
275
+ return doc;
276
+ }
277
+
278
+ VALUE rb_bson_byte_buffer_get_array(VALUE self){
279
+ byte_buffer_t *b;
280
+ VALUE array = Qnil;
281
+ uint8_t type;
282
+
283
+ TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b);
284
+
285
+ pvt_validate_length(b);
286
+
287
+ array = rb_ary_new();
288
+ while((type = pvt_get_type_byte(b)) != 0){
289
+ pvt_skip_cstring(b);
290
+ rb_ary_push(array, pvt_read_field(b, self, type));
291
+ }
292
+ RB_GC_GUARD(array);
293
+ return array;
294
+ }
@@ -0,0 +1,55 @@
1
+ /*
2
+ * Copyright (C) 2009-2019 MongoDB, Inc.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ #include "bson-native.h"
18
+
19
+ /**
20
+ * Holds the machine id hash for object id generation.
21
+ */
22
+ static char rb_bson_machine_id_hash[HOST_NAME_HASH_MAX];
23
+
24
+ void rb_bson_generate_machine_id(VALUE rb_md5_class, char *rb_bson_machine_id)
25
+ {
26
+ VALUE digest = rb_funcall(rb_md5_class, rb_intern("digest"), 1, rb_str_new2(rb_bson_machine_id));
27
+ memcpy(rb_bson_machine_id_hash, RSTRING_PTR(digest), RSTRING_LEN(digest));
28
+ }
29
+
30
+ /**
31
+ * Generate the next object id.
32
+ */
33
+ VALUE rb_bson_object_id_generator_next(int argc, VALUE* args, VALUE self)
34
+ {
35
+ char bytes[12];
36
+ uint32_t t;
37
+ uint32_t c;
38
+ uint16_t pid = BSON_UINT16_TO_BE(getpid());
39
+
40
+ if (argc == 0 || (argc == 1 && *args == Qnil)) {
41
+ t = BSON_UINT32_TO_BE((int) time(NULL));
42
+ }
43
+ else {
44
+ t = BSON_UINT32_TO_BE(NUM2ULONG(rb_funcall(*args, rb_intern("to_i"), 0)));
45
+ }
46
+
47
+ c = BSON_UINT32_TO_BE(rb_bson_object_id_counter << 8);
48
+
49
+ memcpy(&bytes, &t, 4);
50
+ memcpy(&bytes[4], rb_bson_machine_id_hash, 3);
51
+ memcpy(&bytes[7], &pid, 2);
52
+ memcpy(&bytes[9], &c, 3);
53
+ rb_bson_object_id_counter++;
54
+ return rb_str_new(bytes, 12);
55
+ }
@@ -0,0 +1,637 @@
1
+ /*
2
+ * Copyright (C) 2009-2019 MongoDB, Inc.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ #include "bson-native.h"
18
+ #include <ruby/encoding.h>
19
+
20
+ typedef struct{
21
+ byte_buffer_t *b;
22
+ VALUE buffer;
23
+ VALUE validating_keys;
24
+ } put_hash_context;
25
+
26
+ static void pvt_replace_int32(byte_buffer_t *b, int32_t position, int32_t newval);
27
+ static void pvt_put_field(byte_buffer_t *b, VALUE rb_buffer, VALUE val, VALUE validating_keys);
28
+ static void pvt_put_byte(byte_buffer_t *b, const char byte);
29
+ static void pvt_put_int32(byte_buffer_t *b, const int32_t i32);
30
+ static void pvt_put_int64(byte_buffer_t *b, const int64_t i);
31
+ static void pvt_put_double(byte_buffer_t *b, double f);
32
+ static void pvt_put_cstring(byte_buffer_t *b, const char *str, int32_t length, const char *data_type);
33
+ static void pvt_put_bson_key(byte_buffer_t *b, VALUE string, VALUE validating_keys);
34
+ static VALUE pvt_bson_byte_buffer_put_bson_partial_string(VALUE self, const char *str, int32_t length);
35
+ static VALUE pvt_bson_byte_buffer_put_binary_string(VALUE self, const char *str, int32_t length);
36
+
37
+ static int fits_int32(int64_t i64){
38
+ return i64 >= INT32_MIN && i64 <= INT32_MAX;
39
+ }
40
+
41
+ void pvt_put_field(byte_buffer_t *b, VALUE rb_buffer, VALUE val, VALUE validating_keys){
42
+ switch(TYPE(val)){
43
+ case T_BIGNUM:
44
+ case T_FIXNUM:{
45
+ int64_t i64= NUM2LL(val);
46
+ if(fits_int32(i64)){
47
+ pvt_put_int32(b, (int32_t)i64);
48
+ }else{
49
+ pvt_put_int64(b, i64);
50
+ }
51
+ break;
52
+ }
53
+ case T_FLOAT:
54
+ pvt_put_double(b, NUM2DBL(val));
55
+ break;
56
+ case T_ARRAY:
57
+ rb_bson_byte_buffer_put_array(rb_buffer, val, validating_keys);
58
+ break;
59
+ case T_TRUE:
60
+ pvt_put_byte(b, 1);
61
+ break;
62
+ case T_FALSE:
63
+ pvt_put_byte(b, 0);
64
+ break;
65
+ case T_HASH:
66
+ rb_bson_byte_buffer_put_hash(rb_buffer, val, validating_keys);
67
+ break;
68
+ default:{
69
+ rb_funcall(val, rb_intern("to_bson"), 2, rb_buffer, validating_keys);
70
+ break;
71
+ }
72
+ }
73
+ }
74
+
75
+ void pvt_put_byte(byte_buffer_t *b, const char byte)
76
+ {
77
+ ENSURE_BSON_WRITE(b, 1);
78
+ *WRITE_PTR(b) = byte;
79
+ b->write_position += 1;
80
+
81
+ }
82
+
83
+ /* The docstring is in init.c. */
84
+ VALUE rb_bson_byte_buffer_put_byte(VALUE self, VALUE byte)
85
+ {
86
+ byte_buffer_t *b;
87
+ const char *str;
88
+ size_t length;
89
+
90
+ if (!RB_TYPE_P(byte, T_STRING))
91
+ rb_raise(rb_eArgError, "A string argument is required for put_byte");
92
+
93
+ str = RSTRING_PTR(byte);
94
+ length = RSTRING_LEN(byte);
95
+
96
+ if (length != 1) {
97
+ rb_raise(rb_eArgError, "put_byte requires a string of length 1");
98
+ }
99
+
100
+ TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b);
101
+ ENSURE_BSON_WRITE(b, 1);
102
+ memcpy(WRITE_PTR(b), str, 1);
103
+ b->write_position += 1;
104
+
105
+ return self;
106
+ }
107
+
108
+ /* The docstring is in init.c. */
109
+ VALUE rb_bson_byte_buffer_put_bytes(VALUE self, VALUE bytes)
110
+ {
111
+ byte_buffer_t *b;
112
+ const char *str;
113
+ size_t length;
114
+
115
+ if (!RB_TYPE_P(bytes, T_STRING) && !RB_TYPE_P(bytes, RUBY_T_DATA))
116
+ rb_raise(rb_eArgError, "Invalid input");
117
+
118
+ str = RSTRING_PTR(bytes);
119
+ length = RSTRING_LEN(bytes);
120
+
121
+ TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b);
122
+ ENSURE_BSON_WRITE(b, length);
123
+ memcpy(WRITE_PTR(b), str, length);
124
+ b->write_position += length;
125
+ return self;
126
+ }
127
+
128
+ /* write the byte denoting the BSON type for the passed object*/
129
+ void pvt_put_type_byte(byte_buffer_t *b, VALUE val){
130
+ switch(TYPE(val)){
131
+ case T_BIGNUM:
132
+ case T_FIXNUM:
133
+ if(fits_int32(NUM2LL(val))){
134
+ pvt_put_byte(b, BSON_TYPE_INT32);
135
+ }else{
136
+ pvt_put_byte(b, BSON_TYPE_INT64);
137
+ }
138
+ break;
139
+ case T_STRING:
140
+ pvt_put_byte(b, BSON_TYPE_STRING);
141
+ break;
142
+ case T_ARRAY:
143
+ pvt_put_byte(b, BSON_TYPE_ARRAY);
144
+ break;
145
+ case T_TRUE:
146
+ case T_FALSE:
147
+ pvt_put_byte(b, BSON_TYPE_BOOLEAN);
148
+ break;
149
+ case T_HASH:
150
+ pvt_put_byte(b, BSON_TYPE_DOCUMENT);
151
+ break;
152
+ case T_FLOAT:
153
+ pvt_put_byte(b, BSON_TYPE_DOUBLE);
154
+ break;
155
+ default:{
156
+ VALUE type = rb_funcall(val, rb_intern("bson_type"),0);
157
+ RB_GC_GUARD(type);
158
+ pvt_put_byte(b, *RSTRING_PTR(type));
159
+ break;
160
+ }
161
+ }
162
+ }
163
+
164
+ /**
165
+ * Write a binary string (i.e. one potentially including null bytes)
166
+ * to byte buffer. length is the number of bytes to write.
167
+ * If str is null terminated, length does not include the terminating null.
168
+ */
169
+ VALUE pvt_bson_byte_buffer_put_binary_string(VALUE self, const char *str, int32_t length)
170
+ {
171
+ byte_buffer_t *b;
172
+ int32_t length_le;
173
+
174
+ rb_bson_utf8_validate(str, length, true, "String");
175
+
176
+ /* Even though we are storing binary data, and including the length
177
+ * of it, the bson spec still demands the (useless) trailing null.
178
+ */
179
+ length_le = BSON_UINT32_TO_LE(length + 1);
180
+
181
+ TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b);
182
+ ENSURE_BSON_WRITE(b, length + 5);
183
+ memcpy(WRITE_PTR(b), &length_le, 4);
184
+ b->write_position += 4;
185
+ memcpy(WRITE_PTR(b), str, length);
186
+ b->write_position += length;
187
+ pvt_put_byte(b, 0);
188
+
189
+ return self;
190
+ }
191
+
192
+ /**
193
+ * Encodes +string+ to UTF-8. If +string+ is already in UTF-8, validates that
194
+ * it contains only valid UTF-8 bytes/byte sequences.
195
+ *
196
+ * Raises EncodingError on failure.
197
+ */
198
+ static VALUE pvt_bson_encode_to_utf8(VALUE string) {
199
+ VALUE existing_encoding_name;
200
+ VALUE encoding;
201
+ VALUE utf8_string;
202
+ const char *str;
203
+ int32_t length;
204
+
205
+ existing_encoding_name = rb_funcall(
206
+ rb_funcall(string, rb_intern("encoding"), 0),
207
+ rb_intern("name"), 0);
208
+
209
+ if (strcmp(RSTRING_PTR(existing_encoding_name), "UTF-8") == 0) {
210
+ utf8_string = string;
211
+
212
+ str = RSTRING_PTR(utf8_string);
213
+ length = RSTRING_LEN(utf8_string);
214
+
215
+ rb_bson_utf8_validate(str, length, true, "String");
216
+ } else {
217
+ encoding = rb_enc_str_new_cstr("UTF-8", rb_utf8_encoding());
218
+ utf8_string = rb_funcall(string, rb_intern("encode"), 1, encoding);
219
+ RB_GC_GUARD(encoding);
220
+ }
221
+
222
+ return utf8_string;
223
+ }
224
+
225
+ /* The docstring is in init.c. */
226
+ VALUE rb_bson_byte_buffer_put_string(VALUE self, VALUE string)
227
+ {
228
+ VALUE utf8_string;
229
+ const char *str;
230
+ int32_t length;
231
+
232
+ utf8_string = pvt_bson_encode_to_utf8(string);
233
+ /* At this point utf8_string contains valid utf-8 byte sequences only */
234
+
235
+ str = RSTRING_PTR(utf8_string);
236
+ length = RSTRING_LEN(utf8_string);
237
+
238
+ RB_GC_GUARD(utf8_string);
239
+
240
+ return pvt_bson_byte_buffer_put_binary_string(self, str, length);
241
+ }
242
+
243
+ /**
244
+ * Writes a string (which may form part of a BSON object) to the byte buffer.
245
+ *
246
+ * Note: the string may not contain null bytes, and must be null-terminated.
247
+ * length is the number of bytes to write and does not include the null
248
+ * terminator.
249
+ */
250
+ VALUE pvt_bson_byte_buffer_put_bson_partial_string(VALUE self, const char *str, int32_t length)
251
+ {
252
+ byte_buffer_t *b;
253
+ TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b);
254
+ pvt_put_cstring(b, str, length, "String");
255
+ return self;
256
+ }
257
+
258
+ /* The docstring is in init.c. */
259
+ VALUE rb_bson_byte_buffer_put_cstring(VALUE self, VALUE obj)
260
+ {
261
+ VALUE string;
262
+ const char *str;
263
+ int32_t length;
264
+
265
+ switch (TYPE(obj)) {
266
+ case T_STRING:
267
+ string = pvt_bson_encode_to_utf8(obj);
268
+ break;
269
+ case T_SYMBOL:
270
+ string = rb_sym2str(obj);
271
+ break;
272
+ case T_FIXNUM:
273
+ string = rb_fix2str(obj, 10);
274
+ break;
275
+ default:
276
+ rb_raise(rb_eTypeError, "Invalid type for put_cstring");
277
+ }
278
+
279
+ str = RSTRING_PTR(string);
280
+ length = RSTRING_LEN(string);
281
+ RB_GC_GUARD(string);
282
+ return pvt_bson_byte_buffer_put_bson_partial_string(self, str, length);
283
+ }
284
+
285
+ /**
286
+ * Writes a string (which may form part of a BSON object) to the byte buffer.
287
+ *
288
+ * Note: the string may not contain null bytes, and must be null-terminated.
289
+ * length is the number of bytes to write and does not include the null
290
+ * terminator.
291
+ *
292
+ * data_type is the type of data being written, e.g. "String" or "Key".
293
+ */
294
+ void pvt_put_cstring(byte_buffer_t *b, const char *str, int32_t length, const char *data_type)
295
+ {
296
+ int bytes_to_write;
297
+ rb_bson_utf8_validate(str, length, false, data_type);
298
+ bytes_to_write = length + 1;
299
+ ENSURE_BSON_WRITE(b, bytes_to_write);
300
+ memcpy(WRITE_PTR(b), str, bytes_to_write);
301
+ b->write_position += bytes_to_write;
302
+ }
303
+
304
+ /* The docstring is in init.c. */
305
+ VALUE rb_bson_byte_buffer_put_symbol(VALUE self, VALUE symbol)
306
+ {
307
+ VALUE symbol_str = rb_sym_to_s(symbol);
308
+ const char *str = RSTRING_PTR(symbol_str);
309
+ const int32_t length = RSTRING_LEN(symbol_str);
310
+
311
+ RB_GC_GUARD(symbol_str);
312
+ return pvt_bson_byte_buffer_put_binary_string(self, str, length);
313
+ }
314
+
315
+ /**
316
+ * Write a hash key to the byte buffer, validating it if requested
317
+ */
318
+ void pvt_put_bson_key(byte_buffer_t *b, VALUE string, VALUE validating_keys){
319
+ char *c_str = RSTRING_PTR(string);
320
+ size_t length = RSTRING_LEN(string);
321
+
322
+ if (RTEST(validating_keys)) {
323
+ if (length > 0 && (c_str[0] == '$' || memchr(c_str, '.', length))) {
324
+ rb_exc_raise(rb_funcall(rb_bson_illegal_key, rb_intern("new"), 1, string));
325
+ }
326
+ }
327
+
328
+ pvt_put_cstring(b, c_str, length, "Key");
329
+ }
330
+
331
+ void pvt_replace_int32(byte_buffer_t *b, int32_t position, int32_t newval)
332
+ {
333
+ const int32_t i32 = BSON_UINT32_TO_LE(newval);
334
+ memcpy(READ_PTR(b) + position, &i32, 4);
335
+ }
336
+
337
+ /* The docstring is in init.c. */
338
+ VALUE rb_bson_byte_buffer_replace_int32(VALUE self, VALUE position, VALUE newval)
339
+ {
340
+ byte_buffer_t *b;
341
+ long _position;
342
+
343
+ _position = NUM2LONG(position);
344
+ if (_position < 0) {
345
+ rb_raise(rb_eArgError, "Position given to replace_int32 cannot be negative: %ld", _position);
346
+ }
347
+
348
+ TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b);
349
+
350
+ if (b->write_position < 4) {
351
+ rb_raise(rb_eArgError, "Buffer does not have enough data to use replace_int32");
352
+ }
353
+
354
+ if ((size_t) _position > b->write_position - 4) {
355
+ rb_raise(rb_eArgError, "Position given to replace_int32 is out of bounds: %ld", _position);
356
+ }
357
+
358
+ pvt_replace_int32(b, _position, NUM2LONG(newval));
359
+
360
+ return self;
361
+ }
362
+
363
+ /* The docstring is in init.c. */
364
+ VALUE rb_bson_byte_buffer_put_int32(VALUE self, VALUE i)
365
+ {
366
+ byte_buffer_t *b;
367
+ const int32_t i32 = NUM2INT(i);
368
+
369
+ TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b);
370
+ pvt_put_int32(b, i32);
371
+ return self;
372
+ }
373
+
374
+ void pvt_put_int32(byte_buffer_t *b, const int32_t i)
375
+ {
376
+ const int32_t i32 = BSON_UINT32_TO_LE(i);
377
+ ENSURE_BSON_WRITE(b, 4);
378
+ memcpy(WRITE_PTR(b), &i32, 4);
379
+ b->write_position += 4;
380
+ }
381
+
382
+ /* The docstring is in init.c. */
383
+ VALUE rb_bson_byte_buffer_put_int64(VALUE self, VALUE i)
384
+ {
385
+ byte_buffer_t *b;
386
+ const int64_t i64 = NUM2LL(i);
387
+
388
+ TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b);
389
+ pvt_put_int64(b, i64);
390
+
391
+ return self;
392
+ }
393
+
394
+ void pvt_put_int64(byte_buffer_t *b, const int64_t i)
395
+ {
396
+ const int64_t i64 = BSON_UINT64_TO_LE(i);
397
+
398
+ ENSURE_BSON_WRITE(b, 8);
399
+ memcpy(WRITE_PTR(b), &i64, 8);
400
+ b->write_position += 8;
401
+ }
402
+
403
+ /* The docstring is in init.c. */
404
+ VALUE rb_bson_byte_buffer_put_double(VALUE self, VALUE f)
405
+ {
406
+ byte_buffer_t *b;
407
+ TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b);
408
+ pvt_put_double(b, NUM2DBL(f));
409
+
410
+ return self;
411
+ }
412
+
413
+ void pvt_put_double(byte_buffer_t *b, double f)
414
+ {
415
+ const double d = BSON_DOUBLE_TO_LE(f);
416
+ ENSURE_BSON_WRITE(b, 8);
417
+ memcpy(WRITE_PTR(b), &d, 8);
418
+ b->write_position += 8;
419
+ }
420
+
421
+ /* The docstring is in init.c. */
422
+ VALUE rb_bson_byte_buffer_put_decimal128(VALUE self, VALUE low, VALUE high)
423
+ {
424
+ byte_buffer_t *b;
425
+ const int64_t low64 = BSON_UINT64_TO_LE(NUM2ULL(low));
426
+ const int64_t high64 = BSON_UINT64_TO_LE(NUM2ULL(high));
427
+
428
+ TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b);
429
+ ENSURE_BSON_WRITE(b, 16);
430
+ memcpy(WRITE_PTR(b), &low64, 8);
431
+ b->write_position += 8;
432
+
433
+ memcpy(WRITE_PTR(b), &high64, 8);
434
+ b->write_position += 8;
435
+
436
+ return self;
437
+ }
438
+
439
+ static int put_hash_callback(VALUE key, VALUE val, VALUE context){
440
+ VALUE buffer = ((put_hash_context*)context)->buffer;
441
+ VALUE validating_keys = ((put_hash_context*)context)->validating_keys;
442
+ byte_buffer_t *b = ((put_hash_context*)context)->b;
443
+ VALUE key_str;
444
+
445
+ pvt_put_type_byte(b, val);
446
+
447
+ switch(TYPE(key)){
448
+ case T_STRING:
449
+ pvt_put_bson_key(b, key, validating_keys);
450
+ break;
451
+ case T_SYMBOL:
452
+ key_str = rb_sym_to_s(key);
453
+ RB_GC_GUARD(key_str);
454
+ pvt_put_bson_key(b, key_str, validating_keys);
455
+ break;
456
+ default:
457
+ rb_bson_byte_buffer_put_cstring(buffer, rb_funcall(key, rb_intern("to_bson_key"), 1, validating_keys));
458
+ }
459
+
460
+ pvt_put_field(b, buffer, val, validating_keys);
461
+ return ST_CONTINUE;
462
+ }
463
+
464
+ /* The docstring is in init.c. */
465
+ VALUE rb_bson_byte_buffer_put_hash(VALUE self, VALUE hash, VALUE validating_keys){
466
+ byte_buffer_t *b = NULL;
467
+ put_hash_context context = { NULL };
468
+ size_t position = 0;
469
+ size_t new_position = 0;
470
+ int32_t new_length = 0;
471
+
472
+ TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b);
473
+ Check_Type(hash, T_HASH);
474
+
475
+ position = READ_SIZE(b);
476
+
477
+ /* insert length placeholder */
478
+ pvt_put_int32(b, 0);
479
+ context.buffer = self;
480
+ context.validating_keys = validating_keys;
481
+ context.b = b;
482
+
483
+ rb_hash_foreach(hash, put_hash_callback, (VALUE)&context);
484
+ pvt_put_byte(b, 0);
485
+
486
+ /* update length placeholder with actual value */
487
+ new_position = READ_SIZE(b);
488
+ new_length = new_position - position;
489
+ pvt_replace_int32(b, position, new_length);
490
+
491
+ return self;
492
+ }
493
+
494
+ static const char *index_strings[] = {
495
+ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
496
+ "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21",
497
+ "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32",
498
+ "33", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43",
499
+ "44", "45", "46", "47", "48", "49", "50", "51", "52", "53", "54",
500
+ "55", "56", "57", "58", "59", "60", "61", "62", "63", "64", "65",
501
+ "66", "67", "68", "69", "70", "71", "72", "73", "74", "75", "76",
502
+ "77", "78", "79", "80", "81", "82", "83", "84", "85", "86", "87",
503
+ "88", "89", "90", "91", "92", "93", "94", "95", "96", "97", "98",
504
+ "99", "100", "101", "102", "103", "104", "105", "106", "107", "108", "109",
505
+ "110", "111", "112", "113", "114", "115", "116", "117", "118", "119", "120",
506
+ "121", "122", "123", "124", "125", "126", "127", "128", "129", "130", "131",
507
+ "132", "133", "134", "135", "136", "137", "138", "139", "140", "141", "142",
508
+ "143", "144", "145", "146", "147", "148", "149", "150", "151", "152", "153",
509
+ "154", "155", "156", "157", "158", "159", "160", "161", "162", "163", "164",
510
+ "165", "166", "167", "168", "169", "170", "171", "172", "173", "174", "175",
511
+ "176", "177", "178", "179", "180", "181", "182", "183", "184", "185", "186",
512
+ "187", "188", "189", "190", "191", "192", "193", "194", "195", "196", "197",
513
+ "198", "199", "200", "201", "202", "203", "204", "205", "206", "207", "208",
514
+ "209", "210", "211", "212", "213", "214", "215", "216", "217", "218", "219",
515
+ "220", "221", "222", "223", "224", "225", "226", "227", "228", "229", "230",
516
+ "231", "232", "233", "234", "235", "236", "237", "238", "239", "240", "241",
517
+ "242", "243", "244", "245", "246", "247", "248", "249", "250", "251", "252",
518
+ "253", "254", "255", "256", "257", "258", "259", "260", "261", "262", "263",
519
+ "264", "265", "266", "267", "268", "269", "270", "271", "272", "273", "274",
520
+ "275", "276", "277", "278", "279", "280", "281", "282", "283", "284", "285",
521
+ "286", "287", "288", "289", "290", "291", "292", "293", "294", "295", "296",
522
+ "297", "298", "299", "300", "301", "302", "303", "304", "305", "306", "307",
523
+ "308", "309", "310", "311", "312", "313", "314", "315", "316", "317", "318",
524
+ "319", "320", "321", "322", "323", "324", "325", "326", "327", "328", "329",
525
+ "330", "331", "332", "333", "334", "335", "336", "337", "338", "339", "340",
526
+ "341", "342", "343", "344", "345", "346", "347", "348", "349", "350", "351",
527
+ "352", "353", "354", "355", "356", "357", "358", "359", "360", "361", "362",
528
+ "363", "364", "365", "366", "367", "368", "369", "370", "371", "372", "373",
529
+ "374", "375", "376", "377", "378", "379", "380", "381", "382", "383", "384",
530
+ "385", "386", "387", "388", "389", "390", "391", "392", "393", "394", "395",
531
+ "396", "397", "398", "399", "400", "401", "402", "403", "404", "405", "406",
532
+ "407", "408", "409", "410", "411", "412", "413", "414", "415", "416", "417",
533
+ "418", "419", "420", "421", "422", "423", "424", "425", "426", "427", "428",
534
+ "429", "430", "431", "432", "433", "434", "435", "436", "437", "438", "439",
535
+ "440", "441", "442", "443", "444", "445", "446", "447", "448", "449", "450",
536
+ "451", "452", "453", "454", "455", "456", "457", "458", "459", "460", "461",
537
+ "462", "463", "464", "465", "466", "467", "468", "469", "470", "471", "472",
538
+ "473", "474", "475", "476", "477", "478", "479", "480", "481", "482", "483",
539
+ "484", "485", "486", "487", "488", "489", "490", "491", "492", "493", "494",
540
+ "495", "496", "497", "498", "499", "500", "501", "502", "503", "504", "505",
541
+ "506", "507", "508", "509", "510", "511", "512", "513", "514", "515", "516",
542
+ "517", "518", "519", "520", "521", "522", "523", "524", "525", "526", "527",
543
+ "528", "529", "530", "531", "532", "533", "534", "535", "536", "537", "538",
544
+ "539", "540", "541", "542", "543", "544", "545", "546", "547", "548", "549",
545
+ "550", "551", "552", "553", "554", "555", "556", "557", "558", "559", "560",
546
+ "561", "562", "563", "564", "565", "566", "567", "568", "569", "570", "571",
547
+ "572", "573", "574", "575", "576", "577", "578", "579", "580", "581", "582",
548
+ "583", "584", "585", "586", "587", "588", "589", "590", "591", "592", "593",
549
+ "594", "595", "596", "597", "598", "599", "600", "601", "602", "603", "604",
550
+ "605", "606", "607", "608", "609", "610", "611", "612", "613", "614", "615",
551
+ "616", "617", "618", "619", "620", "621", "622", "623", "624", "625", "626",
552
+ "627", "628", "629", "630", "631", "632", "633", "634", "635", "636", "637",
553
+ "638", "639", "640", "641", "642", "643", "644", "645", "646", "647", "648",
554
+ "649", "650", "651", "652", "653", "654", "655", "656", "657", "658", "659",
555
+ "660", "661", "662", "663", "664", "665", "666", "667", "668", "669", "670",
556
+ "671", "672", "673", "674", "675", "676", "677", "678", "679", "680", "681",
557
+ "682", "683", "684", "685", "686", "687", "688", "689", "690", "691", "692",
558
+ "693", "694", "695", "696", "697", "698", "699", "700", "701", "702", "703",
559
+ "704", "705", "706", "707", "708", "709", "710", "711", "712", "713", "714",
560
+ "715", "716", "717", "718", "719", "720", "721", "722", "723", "724", "725",
561
+ "726", "727", "728", "729", "730", "731", "732", "733", "734", "735", "736",
562
+ "737", "738", "739", "740", "741", "742", "743", "744", "745", "746", "747",
563
+ "748", "749", "750", "751", "752", "753", "754", "755", "756", "757", "758",
564
+ "759", "760", "761", "762", "763", "764", "765", "766", "767", "768", "769",
565
+ "770", "771", "772", "773", "774", "775", "776", "777", "778", "779", "780",
566
+ "781", "782", "783", "784", "785", "786", "787", "788", "789", "790", "791",
567
+ "792", "793", "794", "795", "796", "797", "798", "799", "800", "801", "802",
568
+ "803", "804", "805", "806", "807", "808", "809", "810", "811", "812", "813",
569
+ "814", "815", "816", "817", "818", "819", "820", "821", "822", "823", "824",
570
+ "825", "826", "827", "828", "829", "830", "831", "832", "833", "834", "835",
571
+ "836", "837", "838", "839", "840", "841", "842", "843", "844", "845", "846",
572
+ "847", "848", "849", "850", "851", "852", "853", "854", "855", "856", "857",
573
+ "858", "859", "860", "861", "862", "863", "864", "865", "866", "867", "868",
574
+ "869", "870", "871", "872", "873", "874", "875", "876", "877", "878", "879",
575
+ "880", "881", "882", "883", "884", "885", "886", "887", "888", "889", "890",
576
+ "891", "892", "893", "894", "895", "896", "897", "898", "899", "900", "901",
577
+ "902", "903", "904", "905", "906", "907", "908", "909", "910", "911", "912",
578
+ "913", "914", "915", "916", "917", "918", "919", "920", "921", "922", "923",
579
+ "924", "925", "926", "927", "928", "929", "930", "931", "932", "933", "934",
580
+ "935", "936", "937", "938", "939", "940", "941", "942", "943", "944", "945",
581
+ "946", "947", "948", "949", "950", "951", "952", "953", "954", "955", "956",
582
+ "957", "958", "959", "960", "961", "962", "963", "964", "965", "966", "967",
583
+ "968", "969", "970", "971", "972", "973", "974", "975", "976", "977", "978",
584
+ "979", "980", "981", "982", "983", "984", "985", "986", "987", "988", "989",
585
+ "990", "991", "992", "993", "994", "995", "996", "997", "998", "999"};
586
+
587
+ /**
588
+ * Writes an array index to the byte buffer.
589
+ */
590
+ void pvt_put_array_index(byte_buffer_t *b, int32_t index)
591
+ {
592
+ char buffer[16];
593
+ const char *c_str = NULL;
594
+ size_t length;
595
+
596
+ if (index < 1000) {
597
+ c_str = index_strings[index];
598
+ } else {
599
+ c_str = buffer;
600
+ snprintf(buffer, sizeof(buffer), "%d", index);
601
+ }
602
+ length = strlen(c_str) + 1;
603
+ ENSURE_BSON_WRITE(b, length);
604
+ memcpy(WRITE_PTR(b), c_str, length);
605
+ b->write_position += length;
606
+ }
607
+
608
+ /* The docstring is in init.c. */
609
+ VALUE rb_bson_byte_buffer_put_array(VALUE self, VALUE array, VALUE validating_keys){
610
+ byte_buffer_t *b = NULL;
611
+ size_t new_position = 0;
612
+ int32_t new_length = 0;
613
+ size_t position = 0;
614
+ VALUE *array_element = NULL;
615
+ TypedData_Get_Struct(self, byte_buffer_t, &rb_byte_buffer_data_type, b);
616
+ Check_Type(array, T_ARRAY);
617
+
618
+ position = READ_SIZE(b);
619
+ /* insert length placeholder */
620
+ pvt_put_int32(b, 0);
621
+
622
+ array_element = RARRAY_PTR(array);
623
+
624
+ for(int32_t index=0; index < RARRAY_LEN(array); index++, array_element++){
625
+ pvt_put_type_byte(b, *array_element);
626
+ pvt_put_array_index(b,index);
627
+ pvt_put_field(b, self, *array_element, validating_keys);
628
+ }
629
+ pvt_put_byte(b, 0);
630
+
631
+ /* update length placeholder */
632
+ new_position = READ_SIZE(b);
633
+ new_length = new_position - position;
634
+ pvt_replace_int32(b, position, new_length);
635
+
636
+ return self;
637
+ }