gitlab-cbor 1.0.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 (59) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +25 -0
  3. data/.gitlab-ci.yml +44 -0
  4. data/.travis.yml +24 -0
  5. data/CHANGELOG.md +30 -0
  6. data/ChangeLog +106 -0
  7. data/Gemfile +11 -0
  8. data/README.rdoc +191 -0
  9. data/Rakefile +97 -0
  10. data/ci/test.rb +31 -0
  11. data/doclib/cbor/buffer.rb +193 -0
  12. data/doclib/cbor/core_ext.rb +133 -0
  13. data/doclib/cbor/error.rb +14 -0
  14. data/doclib/cbor/packer.rb +133 -0
  15. data/doclib/cbor/simple.rb +15 -0
  16. data/doclib/cbor/tagged.rb +16 -0
  17. data/doclib/cbor/unpacker.rb +138 -0
  18. data/doclib/cbor.rb +80 -0
  19. data/ext/cbor/buffer.c +693 -0
  20. data/ext/cbor/buffer.h +484 -0
  21. data/ext/cbor/buffer_class.c +561 -0
  22. data/ext/cbor/buffer_class.h +41 -0
  23. data/ext/cbor/cbor.h +69 -0
  24. data/ext/cbor/compat.h +147 -0
  25. data/ext/cbor/core_ext.c +199 -0
  26. data/ext/cbor/core_ext.h +35 -0
  27. data/ext/cbor/extconf.rb +29 -0
  28. data/ext/cbor/packer.c +169 -0
  29. data/ext/cbor/packer.h +370 -0
  30. data/ext/cbor/packer_class.c +345 -0
  31. data/ext/cbor/packer_class.h +40 -0
  32. data/ext/cbor/rbinit.c +57 -0
  33. data/ext/cbor/renamer.h +56 -0
  34. data/ext/cbor/rmem.c +103 -0
  35. data/ext/cbor/rmem.h +118 -0
  36. data/ext/cbor/sysdep.h +139 -0
  37. data/ext/cbor/sysdep_endian.h +59 -0
  38. data/ext/cbor/sysdep_types.h +55 -0
  39. data/ext/cbor/unpacker.c +787 -0
  40. data/ext/cbor/unpacker.h +135 -0
  41. data/ext/cbor/unpacker_class.c +483 -0
  42. data/ext/cbor/unpacker_class.h +39 -0
  43. data/gitlab-cbor.gemspec +27 -0
  44. data/lib/cbor/version.rb +3 -0
  45. data/lib/cbor.rb +6 -0
  46. data/spec/buffer_io_spec.rb +260 -0
  47. data/spec/buffer_spec.rb +576 -0
  48. data/spec/cases.cbor +0 -0
  49. data/spec/cases.cbor_stream +0 -0
  50. data/spec/cases.json +1 -0
  51. data/spec/cases.msg +0 -0
  52. data/spec/cases_compact.msg +0 -0
  53. data/spec/cases_spec.rb +39 -0
  54. data/spec/format_spec.rb +603 -0
  55. data/spec/packer_spec.rb +127 -0
  56. data/spec/random_compat.rb +24 -0
  57. data/spec/spec_helper.rb +68 -0
  58. data/spec/unpacker_spec.rb +260 -0
  59. metadata +189 -0
@@ -0,0 +1,787 @@
1
+ /*
2
+ * CBOR for Ruby
3
+ *
4
+ * Copyright (C) 2013 Carsten Bormann
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License").
7
+ *
8
+ * Based on:
9
+ ***********/
10
+ /*
11
+ * MessagePack for Ruby
12
+ *
13
+ * Copyright (C) 2008-2013 Sadayuki Furuhashi
14
+ *
15
+ * Licensed under the Apache License, Version 2.0 (the "License");
16
+ * you may not use this file except in compliance with the License.
17
+ * You may obtain a copy of the License at
18
+ *
19
+ * http://www.apache.org/licenses/LICENSE-2.0
20
+ *
21
+ * Unless required by applicable law or agreed to in writing, software
22
+ * distributed under the License is distributed on an "AS IS" BASIS,
23
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
24
+ * See the License for the specific language governing permissions and
25
+ * limitations under the License.
26
+ */
27
+
28
+ #include "unpacker.h"
29
+ #include "rmem.h"
30
+ #include <math.h> /* for ldexp */
31
+
32
+ /* work around https://bugs.ruby-lang.org/issues/15779 for now
33
+ * by limiting preallocation to about a half a Mebibyte
34
+ * limit is 2**n-1 (n==16) items so we can avoid a conditional
35
+ */
36
+ #define SANE_PREALLOCATION_MAX 0xFFFFUL
37
+ #define SANE_PREALLOCATE(n) (n & SANE_PREALLOCATION_MAX)
38
+
39
+ #if !defined(DISABLE_RMEM) && !defined(DISABLE_UNPACKER_STACK_RMEM) && \
40
+ MSGPACK_UNPACKER_STACK_CAPACITY * MSGPACK_UNPACKER_STACK_SIZE <= MSGPACK_RMEM_PAGE_SIZE
41
+ #define UNPACKER_STACK_RMEM
42
+ #endif
43
+
44
+ #ifdef UNPACKER_STACK_RMEM
45
+ static msgpack_rmem_t s_stack_rmem;
46
+ #endif
47
+
48
+ void msgpack_unpacker_static_init()
49
+ {
50
+ #ifdef UNPACKER_STACK_RMEM
51
+ msgpack_rmem_init(&s_stack_rmem);
52
+ #endif
53
+
54
+ #ifdef COMPAT_HAVE_ENCODING
55
+ s_enc_utf8 = rb_utf8_encindex();
56
+ #endif
57
+ }
58
+
59
+ void msgpack_unpacker_static_destroy()
60
+ {
61
+ #ifdef UNPACKER_STACK_RMEM
62
+ msgpack_rmem_destroy(&s_stack_rmem);
63
+ #endif
64
+ }
65
+
66
+ #define HEAD_BYTE_REQUIRED IB_UNUSED
67
+
68
+ void msgpack_unpacker_init(msgpack_unpacker_t* uk)
69
+ {
70
+ memset(uk, 0, sizeof(msgpack_unpacker_t));
71
+
72
+ msgpack_buffer_init(UNPACKER_BUFFER_(uk));
73
+
74
+ uk->head_byte = HEAD_BYTE_REQUIRED;
75
+
76
+ uk->last_object = Qnil;
77
+ uk->reading_raw = Qnil;
78
+
79
+ #ifdef UNPACKER_STACK_RMEM
80
+ uk->stack = msgpack_rmem_alloc(&s_stack_rmem);
81
+ /*memset(uk->stack, 0, MSGPACK_UNPACKER_STACK_CAPACITY);*/
82
+ #else
83
+ /*uk->stack = calloc(MSGPACK_UNPACKER_STACK_CAPACITY, sizeof(msgpack_unpacker_stack_t));*/
84
+ uk->stack = malloc(MSGPACK_UNPACKER_STACK_CAPACITY * sizeof(msgpack_unpacker_stack_t));
85
+ #endif
86
+ uk->stack_capacity = MSGPACK_UNPACKER_STACK_CAPACITY;
87
+ }
88
+
89
+ void msgpack_unpacker_destroy(msgpack_unpacker_t* uk)
90
+ {
91
+ #ifdef UNPACKER_STACK_RMEM
92
+ msgpack_rmem_free(&s_stack_rmem, uk->stack);
93
+ #else
94
+ free(uk->stack);
95
+ #endif
96
+
97
+ msgpack_buffer_destroy(UNPACKER_BUFFER_(uk));
98
+ }
99
+
100
+ void msgpack_unpacker_mark(msgpack_unpacker_t* uk)
101
+ {
102
+ rb_gc_mark(uk->last_object);
103
+ rb_gc_mark(uk->reading_raw);
104
+
105
+ msgpack_unpacker_stack_t* s = uk->stack;
106
+ msgpack_unpacker_stack_t* send = uk->stack + uk->stack_depth;
107
+ for(; s < send; s++) {
108
+ rb_gc_mark(s->object);
109
+ rb_gc_mark(s->key);
110
+ }
111
+
112
+ /* See MessagePack_Buffer_wrap */
113
+ /* msgpack_buffer_mark(UNPACKER_BUFFER_(uk)); */
114
+ rb_gc_mark(uk->buffer_ref);
115
+ }
116
+
117
+ void msgpack_unpacker_reset(msgpack_unpacker_t* uk)
118
+ {
119
+ msgpack_buffer_clear(UNPACKER_BUFFER_(uk));
120
+
121
+ uk->head_byte = HEAD_BYTE_REQUIRED;
122
+
123
+ /*memset(uk->stack, 0, sizeof(msgpack_unpacker_t) * uk->stack_depth);*/
124
+ uk->stack_depth = 0;
125
+
126
+ uk->last_object = Qnil;
127
+ uk->reading_raw = Qnil;
128
+ uk->reading_raw_remaining = 0;
129
+ }
130
+
131
+
132
+ /* head byte functions */
133
+ static int read_head_byte(msgpack_unpacker_t* uk)
134
+ {
135
+ int r = msgpack_buffer_read_1(UNPACKER_BUFFER_(uk));
136
+ if(r == -1) {
137
+ return PRIMITIVE_EOF;
138
+ }
139
+ return uk->head_byte = r;
140
+ }
141
+
142
+ static inline int get_head_byte(msgpack_unpacker_t* uk)
143
+ {
144
+ int b = uk->head_byte;
145
+ if(b == HEAD_BYTE_REQUIRED) {
146
+ b = read_head_byte(uk);
147
+ }
148
+ return b;
149
+ }
150
+
151
+ static inline void reset_head_byte(msgpack_unpacker_t* uk)
152
+ {
153
+ uk->head_byte = HEAD_BYTE_REQUIRED;
154
+ }
155
+
156
+ static inline int object_complete(msgpack_unpacker_t* uk, VALUE object)
157
+ {
158
+ uk->last_object = object;
159
+ reset_head_byte(uk);
160
+ return PRIMITIVE_OBJECT_COMPLETE;
161
+ }
162
+
163
+ static inline VALUE object_string_encoding_set(VALUE str, int textflag) {
164
+ #ifdef COMPAT_HAVE_ENCODING
165
+ //str_modifiable(str);
166
+ ENCODING_SET(str, textflag ? s_enc_utf8: s_enc_ascii8bit);
167
+ #endif
168
+ return str;
169
+ }
170
+
171
+ static inline int object_complete_string(msgpack_unpacker_t* uk, VALUE str, int textflag)
172
+ {
173
+ return object_complete(uk, object_string_encoding_set(str, textflag));
174
+ }
175
+
176
+ /* stack funcs */
177
+ static inline msgpack_unpacker_stack_t* _msgpack_unpacker_stack_top(msgpack_unpacker_t* uk)
178
+ {
179
+ return &uk->stack[uk->stack_depth-1];
180
+ }
181
+
182
+ static inline int _msgpack_unpacker_stack_push_tag(msgpack_unpacker_t* uk, enum stack_type_t type, size_t count, VALUE object, uint64_t tag)
183
+ {
184
+ reset_head_byte(uk);
185
+
186
+ if(uk->stack_capacity - uk->stack_depth <= 0) {
187
+ return PRIMITIVE_STACK_TOO_DEEP;
188
+ }
189
+
190
+ msgpack_unpacker_stack_t* next = &uk->stack[uk->stack_depth];
191
+ next->count = count;
192
+ next->type = type;
193
+ next->object = object;
194
+ next->key = Qnil;
195
+ next->tag = tag;
196
+
197
+ uk->stack_depth++;
198
+ return PRIMITIVE_CONTAINER_START;
199
+ }
200
+
201
+ static inline int _msgpack_unpacker_stack_push(msgpack_unpacker_t* uk, enum stack_type_t type, size_t count, VALUE object)
202
+ {
203
+ return _msgpack_unpacker_stack_push_tag(uk, type, count, object, 0);
204
+ }
205
+
206
+ static inline VALUE msgpack_unpacker_stack_pop(msgpack_unpacker_t* uk)
207
+ {
208
+ return --uk->stack_depth;
209
+ }
210
+
211
+ static inline bool msgpack_unpacker_stack_is_empty(msgpack_unpacker_t* uk)
212
+ {
213
+ return uk->stack_depth == 0;
214
+ }
215
+
216
+ #ifdef USE_CASE_RANGE
217
+
218
+ #define SWITCH_RANGE_BEGIN(BYTE) { switch(BYTE) {
219
+ #define SWITCH_RANGE(BYTE, FROM, TO) } case FROM ... TO: {
220
+ #define SWITCH_RANGE_DEFAULT } default: {
221
+ #define SWITCH_RANGE_END } }
222
+
223
+ #else
224
+
225
+ #define SWITCH_RANGE_BEGIN(BYTE) { if(0) {
226
+ #define SWITCH_RANGE(BYTE, FROM, TO) } else if(FROM <= (BYTE) && (BYTE) <= TO) {
227
+ #define SWITCH_RANGE_DEFAULT } else {
228
+ #define SWITCH_RANGE_END } }
229
+
230
+ #endif
231
+
232
+
233
+ #define READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, n) \
234
+ union msgpack_buffer_cast_block_t* cb = msgpack_buffer_read_cast_block(UNPACKER_BUFFER_(uk), n); \
235
+ if(cb == NULL) { \
236
+ return PRIMITIVE_EOF; \
237
+ }
238
+
239
+ static inline bool is_reading_map_key(msgpack_unpacker_t* uk)
240
+ {
241
+ if(uk->stack_depth > 0) {
242
+ msgpack_unpacker_stack_t* top = _msgpack_unpacker_stack_top(uk);
243
+ if(top->type == STACK_TYPE_MAP_KEY || top->type == STACK_TYPE_MAP_KEY_INDEF) {
244
+ return true;
245
+ }
246
+ }
247
+ return false;
248
+ }
249
+
250
+ static int read_raw_body_cont(msgpack_unpacker_t* uk, int textflag)
251
+ {
252
+ size_t length = uk->reading_raw_remaining;
253
+
254
+ if(uk->reading_raw == Qnil) {
255
+ uk->reading_raw = rb_str_buf_new(SANE_PREALLOCATE(length));
256
+ }
257
+
258
+ do {
259
+ size_t n = msgpack_buffer_read_to_string(UNPACKER_BUFFER_(uk), uk->reading_raw, length);
260
+ if(n == 0) {
261
+ return PRIMITIVE_EOF;
262
+ }
263
+ /* update reading_raw_remaining everytime because
264
+ * msgpack_buffer_read_to_string raises IOError */
265
+ uk->reading_raw_remaining = length = length - n;
266
+ } while(length > 0);
267
+
268
+ object_complete_string(uk, uk->reading_raw, textflag);
269
+ uk->reading_raw = Qnil;
270
+ return PRIMITIVE_OBJECT_COMPLETE;
271
+ }
272
+
273
+ static inline int read_raw_body_begin(msgpack_unpacker_t* uk, int textflag)
274
+ {
275
+ /* assuming uk->reading_raw == Qnil */
276
+ uk->textflag = textflag;
277
+
278
+ /* try optimized read */
279
+ size_t length = uk->reading_raw_remaining;
280
+ if(length <= msgpack_buffer_top_readable_size(UNPACKER_BUFFER_(uk))) {
281
+ /* don't use zerocopy for hash keys but get a frozen string directly
282
+ * because rb_hash_aset freezes keys and it causes copying */
283
+ bool will_freeze = is_reading_map_key(uk);
284
+ VALUE string;
285
+ bool as_symbol = will_freeze && textflag && uk->keys_as_symbols;
286
+ string = msgpack_buffer_read_top_as_string(UNPACKER_BUFFER_(uk), length, will_freeze, as_symbol);
287
+ if (as_symbol)
288
+ object_complete(uk, string);
289
+ else {
290
+ object_complete_string(uk, string, textflag);
291
+ if (will_freeze) {
292
+ rb_obj_freeze(string);
293
+ }
294
+ }
295
+
296
+ uk->reading_raw_remaining = 0;
297
+ return PRIMITIVE_OBJECT_COMPLETE;
298
+ }
299
+
300
+ return read_raw_body_cont(uk, textflag);
301
+ }
302
+
303
+ /* speedier version of ldexp for 11-bit numbers */
304
+ static inline double ldexp11(int mant, int exp) {
305
+ #if SOMEBODY_FIXED_LDEXP
306
+ return ldexp(mant, exp);
307
+ #else
308
+ union {
309
+ double d;
310
+ uint64_t u;
311
+ } u;
312
+ u.u = ((mant & 0x3ffULL) << 42) | ((exp + 1033ULL) << 52);
313
+ return u.d;
314
+ #endif
315
+ }
316
+
317
+ #define READ_VAL(uk, ai, val) { \
318
+ int n = 1 << ((ai) & 3); \
319
+ READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, n); \
320
+ switch ((ai) & 3) { \
321
+ case 0: { \
322
+ val = cb->u8; \
323
+ break; \
324
+ } \
325
+ case 1: { \
326
+ val = _msgpack_be16(cb->u16); \
327
+ break; \
328
+ } \
329
+ case 2: { \
330
+ val = _msgpack_be32(cb->u32); \
331
+ break; \
332
+ } \
333
+ case 3: { \
334
+ val = _msgpack_be64(cb->u64); \
335
+ break; \
336
+ } \
337
+ } \
338
+ }
339
+
340
+
341
+ /* All the cases with an immediate value in the AI */
342
+ #define CASE_IMM(n) case ((n*8)): case ((n*8) + 1): case ((n*8) + 2): case ((n*8) + 3): case ((n*8) + 4): case ((n*8) + 5)
343
+ /* The case with additional information */
344
+ #define CASE_AI(n) case ((n*8) + 6)
345
+ /* The case with the reserved and indefinite ai values */
346
+ #define CASE_INDEF(n) case ((n*8) + 7)
347
+
348
+ static int read_primitive(msgpack_unpacker_t* uk)
349
+ {
350
+ if(uk->reading_raw_remaining > 0) {
351
+ return read_raw_body_cont(uk, uk->textflag);
352
+ }
353
+
354
+ int ib = get_head_byte(uk);
355
+ if (ib < 0) {
356
+ return ib;
357
+ }
358
+
359
+ int ai = IB_AI(ib);
360
+ uint64_t val = ai;
361
+
362
+ switch (ib >> 2) {
363
+ CASE_IMM(MT_UNSIGNED): // Positive Fixnum
364
+ return object_complete(uk, INT2FIX(ai));
365
+ CASE_AI(MT_UNSIGNED):
366
+ READ_VAL(uk, ai, val);
367
+ return object_complete(uk, rb_ull2inum(val));
368
+ CASE_IMM(MT_NEGATIVE): // Negative Fixnum
369
+ return object_complete(uk, INT2FIX(~ai));
370
+ CASE_AI(MT_NEGATIVE):
371
+ READ_VAL(uk, ai, val);
372
+ return object_complete(uk,
373
+ (val & 0x8000000000000000
374
+ ? rb_funcall(rb_ull2inum(val), rb_intern("~"), 0)
375
+ : rb_ll2inum(~val)));
376
+ CASE_AI(MT_BYTES): CASE_AI(MT_TEXT):
377
+ READ_VAL(uk, ai, val);
378
+ CASE_IMM(MT_BYTES): // byte string
379
+ CASE_IMM(MT_TEXT): // text string
380
+ if (val == 0) {
381
+ return object_complete_string(uk, rb_str_buf_new(0), ib & IB_TEXTFLAG);
382
+ }
383
+ uk->reading_raw_remaining = val; /* TODO: range checks on val here and below */
384
+ return read_raw_body_begin(uk, ib & IB_TEXTFLAG);
385
+ CASE_AI(MT_ARRAY):
386
+ READ_VAL(uk, ai, val);
387
+ CASE_IMM(MT_ARRAY): // array
388
+ if (val == 0) {
389
+ return object_complete(uk, rb_ary_new());
390
+ }
391
+ return _msgpack_unpacker_stack_push(uk, STACK_TYPE_ARRAY, val, rb_ary_new2(SANE_PREALLOCATE(val)));
392
+ CASE_AI(MT_MAP):
393
+ READ_VAL(uk, ai, val);
394
+ CASE_IMM(MT_MAP): // map
395
+ if (val == 0) {
396
+ return object_complete(uk, rb_hash_new());
397
+ }
398
+ return _msgpack_unpacker_stack_push(uk, STACK_TYPE_MAP_KEY, val*2, rb_hash_new());
399
+ CASE_AI(MT_TAG):
400
+ READ_VAL(uk, ai, val);
401
+ CASE_IMM(MT_TAG): // tag
402
+ return _msgpack_unpacker_stack_push_tag(uk, STACK_TYPE_TAG, 1, Qnil, val);
403
+ case MT_PRIM*8+5:
404
+ switch(ai) {
405
+ case VAL_NIL: // nil
406
+ return object_complete(uk, Qnil);
407
+ case VAL_FALSE: // false
408
+ return object_complete(uk, Qfalse);
409
+ case VAL_TRUE: // true
410
+ return object_complete(uk, Qtrue);
411
+ }
412
+ /* fall through */
413
+ case MT_PRIM*8: case MT_PRIM*8+1: case MT_PRIM*8+2: case MT_PRIM*8+3: case MT_PRIM*8+4:
414
+ return object_complete(uk, rb_struct_new(rb_cCBOR_Simple, INT2FIX(val)));
415
+ CASE_AI(MT_PRIM):
416
+ READ_VAL(uk, ai, val);
417
+ switch (ai) {
418
+ case AI_2: { // half
419
+ int exp = (val >> 10) & 0x1f;
420
+ int mant = val & 0x3ff; /* 10 bits */
421
+ double res;
422
+ if (exp == 0) res = ldexp(mant, -24);
423
+ else if (exp != 31) res = ldexp11(mant + 1024, exp - 25);
424
+ else {
425
+ if (mant == 0)
426
+ res = INFINITY;
427
+ else { /* NAN */
428
+ union {
429
+ uint64_t u64;
430
+ double d;
431
+ } castbuf = { (val & 0x8000) << 48 | 0x7ff0000000000000UL | (uint64_t)mant << 42 };
432
+ return object_complete(uk, rb_float_new(castbuf.d));
433
+ }
434
+ }
435
+ return object_complete(uk, rb_float_new(val & 0x8000 ? -res : res));
436
+ }
437
+ case AI_4: // float
438
+ {
439
+ union {
440
+ uint32_t u32;
441
+ float f;
442
+ } castbuf = { (uint32_t)val }; /* sets Q to 1 for NAN */
443
+ if (castbuf.f == castbuf.f) {
444
+ return object_complete(uk, rb_float_new(castbuf.f));
445
+ } else { /* NAN */
446
+ uint64_t mant = val & 0x7fffff; /* 23 bits */
447
+ union {
448
+ uint64_t u64;
449
+ double d;
450
+ } castbuf1 = { (val & 0x80000000UL) << 32 | 0x7ff0000000000000UL | mant << 29 };
451
+ return object_complete(uk, rb_float_new(castbuf1.d));
452
+ }
453
+ }
454
+ case AI_8: // double
455
+ {
456
+ union {
457
+ uint64_t u64;
458
+ double d;
459
+ } castbuf = { val };
460
+ return object_complete(uk, rb_float_new(castbuf.d));
461
+ }
462
+ default:
463
+ return object_complete(uk, rb_struct_new(rb_cCBOR_Simple, INT2FIX(val)));
464
+ }
465
+ CASE_INDEF(MT_BYTES): CASE_INDEF(MT_TEXT): /* handle string */
466
+ if (ai == AI_INDEF)
467
+ return _msgpack_unpacker_stack_push(uk, STACK_TYPE_STRING_INDEF, ib & IB_TEXTFLAG,
468
+ object_string_encoding_set(rb_str_buf_new(0),
469
+ ib & IB_TEXTFLAG));
470
+ /* fall through */
471
+ CASE_INDEF(MT_ARRAY):
472
+ if (ai == AI_INDEF)
473
+ return _msgpack_unpacker_stack_push(uk, STACK_TYPE_ARRAY_INDEF, 0, rb_ary_new2(0));
474
+ /* fall through */
475
+ CASE_INDEF(MT_MAP):
476
+ if (ai == AI_INDEF)
477
+ return _msgpack_unpacker_stack_push(uk, STACK_TYPE_MAP_KEY_INDEF, 0, rb_hash_new());
478
+ /* fall through */
479
+ CASE_INDEF(MT_PRIM):
480
+ if (ai == AI_INDEF)
481
+ return PRIMITIVE_BREAK;
482
+ /* fall through */
483
+ }
484
+ return PRIMITIVE_INVALID_BYTE;
485
+ }
486
+
487
+
488
+ int msgpack_unpacker_read_container_header(msgpack_unpacker_t* uk, uint64_t* result_size, int ib)
489
+ {
490
+ int b = get_head_byte(uk);
491
+ if(b < 0) {
492
+ return b;
493
+ }
494
+
495
+ if(ib <= b && b < (ib + AI_1)) {
496
+ *result_size = IB_AI(b);
497
+ } else if((b & ~0x3) == (ib + AI_1)) {
498
+ uint64_t val;
499
+ READ_VAL(uk, b, val);
500
+ *result_size = val;
501
+ } else {
502
+ return PRIMITIVE_UNEXPECTED_TYPE; /* including INDEF! */
503
+ }
504
+
505
+ reset_head_byte(uk);
506
+ return 0;
507
+ }
508
+
509
+
510
+ int msgpack_unpacker_read_array_header(msgpack_unpacker_t* uk, uint64_t* result_size) {
511
+ return msgpack_unpacker_read_container_header(uk, result_size, IB_ARRAY);
512
+ }
513
+
514
+ int msgpack_unpacker_read_map_header(msgpack_unpacker_t* uk, uint64_t* result_size) {
515
+ return msgpack_unpacker_read_container_header(uk, result_size, IB_MAP);
516
+ }
517
+
518
+ static VALUE msgpack_unpacker_process_tag(msgpack_unpacker_t* uk, uint64_t tag, VALUE v) {
519
+ VALUE res = v;
520
+ switch (tag) {
521
+ case TAG_TIME_EPOCH: {
522
+ return rb_funcall(rb_cTime, rb_intern("at"), 1, v);
523
+ }
524
+ case TAG_RE: {
525
+ /* Reconstructing a Regexp runs the decoded data through Regexp.new,
526
+ which the caller may not want when decoding input from an untrusted
527
+ source. Only do it when the caller opts in with
528
+ reconstruct_from_tags: [35]; otherwise return the value as a generic
529
+ tagged object. */
530
+ if (!uk->reconstruct_regexp)
531
+ goto unknown_tag;
532
+ return rb_funcall(rb_cRegexp, rb_intern("new"), 1, v);
533
+ }
534
+ case TAG_URI: {
535
+ /* Likewise, building a URI from the decoded value is opt-in via
536
+ reconstruct_from_tags: [32]. */
537
+ if (!uk->reconstruct_uri)
538
+ goto unknown_tag;
539
+ if (!rb_const_defined(rb_cObject, rb_intern("URI")))
540
+ goto unknown_tag;
541
+ return rb_funcall(rb_const_get(rb_cObject, rb_intern("URI")),
542
+ rb_intern("parse"), 1, v);
543
+ }
544
+ case TAG_BIGNUM_NEG:
545
+ case TAG_BIGNUM:
546
+ /* check object is a byte string */
547
+ if (rb_type(v) != T_STRING)
548
+ break; /* XXX: really should error out here */
549
+ #ifdef COMPAT_HAVE_ENCODING
550
+ if (ENCODING_GET(v) != s_enc_ascii8bit)
551
+ break; /* XXX: really should error out here */
552
+ #endif
553
+ {
554
+ char *sp = RSTRING_PTR(v);
555
+ size_t slen = RSTRING_LEN(v);
556
+ while (slen && *sp == 0) {
557
+ slen--;
558
+ sp++;
559
+ }
560
+
561
+ #ifdef HAVE_RB_INTEGER_UNPACK
562
+
563
+ res = rb_integer_unpack(sp, slen, 1, 0, INTEGER_PACK_BIG_ENDIAN);
564
+ /* (const void *words, size_t numwords, size_t wordsize, size_t nails, int flags); */
565
+
566
+ #else
567
+
568
+ #ifndef CANT_DO_BIGNUMS_FAST_ON_THIS_PLATFORM
569
+ int ndig = (slen + SIZEOF_BDIGITS - 1)/SIZEOF_BDIGITS;
570
+ res = rb_big_new(ndig, 1);
571
+ /* compute number RSTRING_PTR(v) */
572
+ if (ndig) {
573
+ BDIGIT *ds = RBIGNUM_DIGITS(res);
574
+ int missbytes = ndig*SIZEOF_BDIGITS - slen; /* 0..SIZEOF_BDIGITS - 1 */
575
+ union {
576
+ char msdig_str[SIZEOF_BDIGITS];
577
+ BDIGIT msdig_bd;
578
+ } u;
579
+ u.msdig_bd = 0;
580
+ memcpy(u.msdig_str + missbytes, sp, SIZEOF_BDIGITS - missbytes);
581
+ ds[ndig-1] = NTOHBDIGIT(u.msdig_bd);
582
+ sp += SIZEOF_BDIGITS - missbytes;
583
+ while (--ndig > 0) {
584
+ memcpy(u.msdig_str, sp, SIZEOF_BDIGITS);
585
+ ds[ndig-1] = NTOHBDIGIT(u.msdig_bd);
586
+ sp += SIZEOF_BDIGITS;
587
+ }
588
+ }
589
+ #else
590
+ {
591
+ /* This is a slow workaround only... But a working one. */
592
+ char *hex = ALLOC_N(char, 2 * slen + 1);
593
+ char *p = hex;
594
+ while (slen) {
595
+ sprintf(p, "%02x", *sp++ & 0xFF);
596
+ p += 2;
597
+ slen--;
598
+ }
599
+ *p = 0;
600
+ res = rb_cstr2inum(hex, 16);
601
+ xfree(hex);
602
+ }
603
+ #endif
604
+ #endif
605
+ if (tag == TAG_BIGNUM) /* non-negative */
606
+ #ifndef CANT_DO_BIGNUMS_FAST_ON_THIS_PLATFORM
607
+ return rb_big_norm(res);
608
+ #else
609
+ return res;
610
+ #endif
611
+ else
612
+ return rb_funcall(res, rb_intern("~"), 0); /* should be rb_big_neg(), but that is static. */
613
+ }
614
+ }
615
+ unknown_tag:
616
+ /* common return for unknown tags */
617
+ return rb_struct_new(rb_cCBOR_Tagged, rb_ull2inum(tag), v);
618
+ }
619
+
620
+ int msgpack_unpacker_read(msgpack_unpacker_t* uk, size_t target_stack_depth)
621
+ {
622
+ while(true) {
623
+ int r = read_primitive(uk);
624
+ if(r < 0) {
625
+ return r;
626
+ }
627
+ if(r == PRIMITIVE_CONTAINER_START) {
628
+ continue;
629
+ }
630
+ /* PRIMITIVE_OBJECT_COMPLETE */
631
+
632
+ if(msgpack_unpacker_stack_is_empty(uk)) {
633
+ if (r == PRIMITIVE_BREAK)
634
+ return PRIMITIVE_INVALID_BYTE;
635
+ return PRIMITIVE_OBJECT_COMPLETE;
636
+ }
637
+
638
+ container_completed:
639
+ {
640
+ msgpack_unpacker_stack_t* top = _msgpack_unpacker_stack_top(uk);
641
+ if (top->type <= STACK_TYPE_MAP_VALUE_INDEF && r == PRIMITIVE_BREAK)
642
+ return PRIMITIVE_INVALID_BYTE;
643
+ switch(top->type) {
644
+ case STACK_TYPE_ARRAY:
645
+ rb_ary_push(top->object, uk->last_object);
646
+ break;
647
+ case STACK_TYPE_MAP_KEY:
648
+ top->key = uk->last_object;
649
+ top->type = STACK_TYPE_MAP_VALUE;
650
+ break;
651
+ case STACK_TYPE_MAP_VALUE:
652
+ rb_hash_aset(top->object, top->key, uk->last_object);
653
+ top->type = STACK_TYPE_MAP_KEY;
654
+ break;
655
+ case STACK_TYPE_TAG:
656
+ object_complete(uk, msgpack_unpacker_process_tag(uk, top->tag, uk->last_object));
657
+ goto done;
658
+
659
+ case STACK_TYPE_ARRAY_INDEF:
660
+ if (r == PRIMITIVE_BREAK)
661
+ goto complete;
662
+ rb_ary_push(top->object, uk->last_object);
663
+ continue;
664
+ case STACK_TYPE_MAP_KEY_INDEF:
665
+ if (r == PRIMITIVE_BREAK)
666
+ goto complete;
667
+ top->key = uk->last_object;
668
+ top->type = STACK_TYPE_MAP_VALUE_INDEF;
669
+ continue;
670
+ case STACK_TYPE_MAP_VALUE_INDEF:
671
+ rb_hash_aset(top->object, top->key, uk->last_object);
672
+ top->type = STACK_TYPE_MAP_KEY_INDEF;
673
+ continue;
674
+ case STACK_TYPE_STRING_INDEF:
675
+ if (r == PRIMITIVE_BREAK) {
676
+ object_complete_string(uk, top->object, (int)top->count); /* use count as textflag */
677
+ goto done;
678
+ }
679
+ if (!RB_TYPE_P(uk->last_object, T_STRING))
680
+ return PRIMITIVE_INVALID_BYTE;
681
+ #ifdef COMPAT_HAVE_ENCODING /* XXX */
682
+ if (ENCODING_GET(top->object) != ENCODING_GET(uk->last_object))
683
+ return PRIMITIVE_INVALID_BYTE;
684
+ #endif
685
+ rb_str_append(top->object, uk->last_object);
686
+ continue;
687
+ }
688
+ size_t count = --top->count;
689
+
690
+ if(count == 0) {
691
+ complete:;
692
+ object_complete(uk, top->object);
693
+ done:;
694
+ if(msgpack_unpacker_stack_pop(uk) <= target_stack_depth) {
695
+ return PRIMITIVE_OBJECT_COMPLETE;
696
+ }
697
+ r = PRIMITIVE_OBJECT_COMPLETE;
698
+ goto container_completed;
699
+ }
700
+ }
701
+ }
702
+ }
703
+
704
+ int msgpack_unpacker_skip(msgpack_unpacker_t* uk, size_t target_stack_depth)
705
+ {
706
+ while(true) {
707
+ int r = read_primitive(uk);
708
+ if(r < 0) {
709
+ return r;
710
+ }
711
+ if(r == PRIMITIVE_CONTAINER_START) {
712
+ continue;
713
+ }
714
+ /* PRIMITIVE_OBJECT_COMPLETE */
715
+
716
+ if(msgpack_unpacker_stack_is_empty(uk)) {
717
+ return PRIMITIVE_OBJECT_COMPLETE;
718
+ }
719
+
720
+ container_completed:
721
+ {
722
+ msgpack_unpacker_stack_t* top = _msgpack_unpacker_stack_top(uk);
723
+
724
+ /* this section optimized out */
725
+ // TODO object_complete still creates objects which should be optimized out
726
+ /* XXX: check INDEF! */
727
+
728
+ size_t count = --top->count;
729
+
730
+ if(count == 0) {
731
+ object_complete(uk, Qnil);
732
+ if(msgpack_unpacker_stack_pop(uk) <= target_stack_depth) {
733
+ return PRIMITIVE_OBJECT_COMPLETE;
734
+ }
735
+ goto container_completed;
736
+ }
737
+ }
738
+ }
739
+ }
740
+
741
+ /* dead code, but keep it for comparison purposes */
742
+
743
+ static enum msgpack_unpacker_object_type msgpack_unpacker_object_types_per_mt[] = {
744
+ TYPE_INTEGER, TYPE_INTEGER,
745
+ TYPE_RAW, TYPE_RAW, /* XXX */
746
+ TYPE_ARRAY, TYPE_MAP,
747
+ TYPE_INTEGER, /* XXX */
748
+ TYPE_NIL /* see below: */
749
+ };
750
+
751
+ static enum msgpack_unpacker_object_type msgpack_unpacker_object_types_per_ai[] = {
752
+ PRIMITIVE_INVALID_BYTE, PRIMITIVE_INVALID_BYTE, PRIMITIVE_INVALID_BYTE, PRIMITIVE_INVALID_BYTE,
753
+ PRIMITIVE_INVALID_BYTE, PRIMITIVE_INVALID_BYTE, PRIMITIVE_INVALID_BYTE, PRIMITIVE_INVALID_BYTE,
754
+ PRIMITIVE_INVALID_BYTE, PRIMITIVE_INVALID_BYTE, PRIMITIVE_INVALID_BYTE, PRIMITIVE_INVALID_BYTE,
755
+ PRIMITIVE_INVALID_BYTE, PRIMITIVE_INVALID_BYTE, PRIMITIVE_INVALID_BYTE, PRIMITIVE_INVALID_BYTE,
756
+ PRIMITIVE_INVALID_BYTE, PRIMITIVE_INVALID_BYTE, PRIMITIVE_INVALID_BYTE, PRIMITIVE_INVALID_BYTE,
757
+ TYPE_BOOLEAN, TYPE_BOOLEAN, TYPE_NIL, PRIMITIVE_INVALID_BYTE, /* XXX */
758
+ PRIMITIVE_INVALID_BYTE, TYPE_FLOAT, TYPE_FLOAT, TYPE_FLOAT,
759
+ PRIMITIVE_INVALID_BYTE, PRIMITIVE_INVALID_BYTE, PRIMITIVE_INVALID_BYTE, PRIMITIVE_INVALID_BYTE,
760
+ };
761
+
762
+ int msgpack_unpacker_peek_next_object_type(msgpack_unpacker_t* uk)
763
+ {
764
+ int ib = get_head_byte(uk);
765
+ if (ib < 0) {
766
+ return ib;
767
+ }
768
+
769
+ int t = msgpack_unpacker_object_types_per_mt[IB_MT(ib)];
770
+ if (t == TYPE_NIL) {
771
+ t = msgpack_unpacker_object_types_per_ai[IB_AI(ib)];
772
+ }
773
+ return t;
774
+ }
775
+
776
+ int msgpack_unpacker_skip_nil(msgpack_unpacker_t* uk)
777
+ {
778
+ int b = get_head_byte(uk);
779
+ if(b < 0) {
780
+ return b;
781
+ }
782
+ if (b == IB_NIL) {
783
+ return 1;
784
+ }
785
+ return 0;
786
+ }
787
+