hx_cbor 2021.8.20

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +30 -0
  3. data/.travis.yml +24 -0
  4. data/ChangeLog +106 -0
  5. data/Gemfile +11 -0
  6. data/README.rdoc +191 -0
  7. data/Rakefile +97 -0
  8. data/doclib/cbor.rb +80 -0
  9. data/doclib/cbor/buffer.rb +193 -0
  10. data/doclib/cbor/core_ext.rb +133 -0
  11. data/doclib/cbor/error.rb +14 -0
  12. data/doclib/cbor/packer.rb +133 -0
  13. data/doclib/cbor/simple.rb +15 -0
  14. data/doclib/cbor/tagged.rb +16 -0
  15. data/doclib/cbor/unpacker.rb +138 -0
  16. data/ext/cbor/3424.i.rb +29 -0
  17. data/ext/cbor/buffer.c +693 -0
  18. data/ext/cbor/buffer.h +484 -0
  19. data/ext/cbor/buffer_class.c +516 -0
  20. data/ext/cbor/buffer_class.h +41 -0
  21. data/ext/cbor/cbor.h +69 -0
  22. data/ext/cbor/compat.h +147 -0
  23. data/ext/cbor/core_ext.c +201 -0
  24. data/ext/cbor/core_ext.h +35 -0
  25. data/ext/cbor/example.rb +10 -0
  26. data/ext/cbor/extconf.rb +29 -0
  27. data/ext/cbor/install.sh +1 -0
  28. data/ext/cbor/packer.c +169 -0
  29. data/ext/cbor/packer.h +362 -0
  30. data/ext/cbor/packer_class.c +304 -0
  31. data/ext/cbor/packer_class.h +39 -0
  32. data/ext/cbor/rbinit.c +51 -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 +784 -0
  40. data/ext/cbor/unpacker.h +135 -0
  41. data/ext/cbor/unpacker_class.c +439 -0
  42. data/ext/cbor/unpacker_class.h +39 -0
  43. data/hx_cbor.gemspec +25 -0
  44. data/lib/cbor.rb +6 -0
  45. data/lib/cbor/version.rb +3 -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 +540 -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 +198 -0
@@ -0,0 +1,784 @@
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 Tebibyte
34
+ * limit is 2**n-1 (n==28) so we can avoid a conditional
35
+ */
36
+ #define SANE_PREALLOCATION_MAX 0xFFFFFFFUL
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
+ printf("returning PRIMITIVE_EOF, %d\n", __LINE__); // Debug. 陈欣
138
+
139
+ return PRIMITIVE_EOF;
140
+ }
141
+ return uk->head_byte = r;
142
+ }
143
+
144
+ static inline int get_head_byte(msgpack_unpacker_t* uk)
145
+ {
146
+ int b = uk->head_byte;
147
+ if(b == HEAD_BYTE_REQUIRED) {
148
+ b = read_head_byte(uk);
149
+ }
150
+ return b;
151
+ }
152
+
153
+ static inline void reset_head_byte(msgpack_unpacker_t* uk)
154
+ {
155
+ uk->head_byte = HEAD_BYTE_REQUIRED;
156
+ }
157
+
158
+ static inline int object_complete(msgpack_unpacker_t* uk, VALUE object)
159
+ {
160
+ uk->last_object = object;
161
+ reset_head_byte(uk);
162
+ return PRIMITIVE_OBJECT_COMPLETE;
163
+ }
164
+
165
+ static inline VALUE object_string_encoding_set(VALUE str, int textflag) {
166
+ #ifdef COMPAT_HAVE_ENCODING
167
+ //str_modifiable(str);
168
+ ENCODING_SET(str, textflag ? s_enc_utf8: s_enc_ascii8bit);
169
+ #endif
170
+ return str;
171
+ }
172
+
173
+ static inline int object_complete_string(msgpack_unpacker_t* uk, VALUE str, int textflag)
174
+ {
175
+ return object_complete(uk, object_string_encoding_set(str, textflag));
176
+ }
177
+
178
+ /* stack funcs */
179
+ static inline msgpack_unpacker_stack_t* _msgpack_unpacker_stack_top(msgpack_unpacker_t* uk)
180
+ {
181
+ return &uk->stack[uk->stack_depth-1];
182
+ }
183
+
184
+ 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)
185
+ {
186
+ reset_head_byte(uk);
187
+
188
+ if(uk->stack_capacity - uk->stack_depth <= 0) {
189
+ return PRIMITIVE_STACK_TOO_DEEP;
190
+ }
191
+
192
+ msgpack_unpacker_stack_t* next = &uk->stack[uk->stack_depth];
193
+ next->count = count;
194
+ next->type = type;
195
+ next->object = object;
196
+ next->key = Qnil;
197
+ next->tag = tag;
198
+
199
+ uk->stack_depth++;
200
+ return PRIMITIVE_CONTAINER_START;
201
+ }
202
+
203
+ static inline int _msgpack_unpacker_stack_push(msgpack_unpacker_t* uk, enum stack_type_t type, size_t count, VALUE object)
204
+ {
205
+ return _msgpack_unpacker_stack_push_tag(uk, type, count, object, 0);
206
+ }
207
+
208
+ static inline VALUE msgpack_unpacker_stack_pop(msgpack_unpacker_t* uk)
209
+ {
210
+ return --uk->stack_depth;
211
+ }
212
+
213
+ static inline bool msgpack_unpacker_stack_is_empty(msgpack_unpacker_t* uk)
214
+ {
215
+ return uk->stack_depth == 0;
216
+ }
217
+
218
+ #ifdef USE_CASE_RANGE
219
+
220
+ #define SWITCH_RANGE_BEGIN(BYTE) { switch(BYTE) {
221
+ #define SWITCH_RANGE(BYTE, FROM, TO) } case FROM ... TO: {
222
+ #define SWITCH_RANGE_DEFAULT } default: {
223
+ #define SWITCH_RANGE_END } }
224
+
225
+ #else
226
+
227
+ #define SWITCH_RANGE_BEGIN(BYTE) { if(0) {
228
+ #define SWITCH_RANGE(BYTE, FROM, TO) } else if(FROM <= (BYTE) && (BYTE) <= TO) {
229
+ #define SWITCH_RANGE_DEFAULT } else {
230
+ #define SWITCH_RANGE_END } }
231
+
232
+ #endif
233
+
234
+
235
+ #define READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, n) \
236
+ union msgpack_buffer_cast_block_t* cb = msgpack_buffer_read_cast_block(UNPACKER_BUFFER_(uk), n); \
237
+ if(cb == NULL) { \
238
+ printf("returning PRIMITIVE_EOF, %d\n", __LINE__); \
239
+ return PRIMITIVE_EOF; \
240
+ }
241
+
242
+ static inline bool is_reading_map_key(msgpack_unpacker_t* uk)
243
+ {
244
+ if(uk->stack_depth > 0) {
245
+ msgpack_unpacker_stack_t* top = _msgpack_unpacker_stack_top(uk);
246
+ if(top->type == STACK_TYPE_MAP_KEY || top->type == STACK_TYPE_MAP_KEY_INDEF) {
247
+ return true;
248
+ }
249
+ }
250
+ return false;
251
+ }
252
+
253
+ static int read_raw_body_cont(msgpack_unpacker_t* uk, int textflag)
254
+ {
255
+ size_t length = uk->reading_raw_remaining;
256
+
257
+ if(uk->reading_raw == Qnil) {
258
+ uk->reading_raw = rb_str_buf_new(SANE_PREALLOCATE(length));
259
+ }
260
+
261
+ do {
262
+ size_t n = msgpack_buffer_read_to_string(UNPACKER_BUFFER_(uk), uk->reading_raw, length);
263
+ if(n == 0) {
264
+ // printf("returning PRIMITIVE_EOF, %d\n", __LINE__); // Debug. 陈欣
265
+
266
+ if (uk->tolerant) // Tolerant
267
+ {
268
+
269
+ break; // Just break. Stop reading.
270
+ } //if (uk->tolerant) // Tolerant
271
+ else // Not tolerant
272
+ {
273
+ return PRIMITIVE_EOF;
274
+
275
+ } //else // Not tolerant
276
+
277
+ }
278
+ /* update reading_raw_remaining everytime because
279
+ * msgpack_buffer_read_to_string raises IOError */
280
+ uk->reading_raw_remaining = length = length - n;
281
+ } while(length > 0);
282
+
283
+ object_complete_string(uk, uk->reading_raw, textflag);
284
+ uk->reading_raw = Qnil;
285
+ return PRIMITIVE_OBJECT_COMPLETE;
286
+ }
287
+
288
+ static inline int read_raw_body_begin(msgpack_unpacker_t* uk, int textflag)
289
+ {
290
+ /* assuming uk->reading_raw == Qnil */
291
+ uk->textflag = textflag;
292
+
293
+ /* try optimized read */
294
+ size_t length = uk->reading_raw_remaining;
295
+
296
+
297
+ if(length <= msgpack_buffer_top_readable_size(UNPACKER_BUFFER_(uk))) {
298
+
299
+ // printf("enough raw length, reading directly, %d, %d\n", length, __LINE__); // Debug. 陈欣
300
+ /* don't use zerocopy for hash keys but get a frozen string directly
301
+ * because rb_hash_aset freezes keys and it causes copying */
302
+ bool will_freeze = is_reading_map_key(uk);
303
+ VALUE string;
304
+ bool as_symbol = will_freeze && textflag && uk->keys_as_symbols;
305
+ string = msgpack_buffer_read_top_as_string(UNPACKER_BUFFER_(uk), length, will_freeze, as_symbol);
306
+ if (as_symbol)
307
+ object_complete(uk, string);
308
+ else {
309
+ object_complete_string(uk, string, textflag);
310
+ if (will_freeze) {
311
+ rb_obj_freeze(string);
312
+ }
313
+ }
314
+
315
+ uk->reading_raw_remaining = 0;
316
+ return PRIMITIVE_OBJECT_COMPLETE;
317
+ }
318
+ else
319
+ {
320
+ // printf("no enough raw length, %d, %d\n", length, __LINE__); // Debug. 陈欣
321
+
322
+ }
323
+
324
+ // printf("calling read_raw_body_cont, %d\n", __LINE__); // Debug. 陈欣
325
+ return read_raw_body_cont(uk, textflag);
326
+ }
327
+
328
+ /* speedier version of ldexp for 11-bit numbers */
329
+ static inline double ldexp11(int mant, int exp) {
330
+ #if SOMEBODY_FIXED_LDEXP
331
+ return ldexp(mant, exp);
332
+ #else
333
+ union {
334
+ double d;
335
+ uint64_t u;
336
+ } u;
337
+ u.u = ((mant & 0x3ffULL) << 42) | ((exp + 1033ULL) << 52);
338
+ return u.d;
339
+ #endif
340
+ }
341
+
342
+ #define READ_VAL(uk, ai, val) { \
343
+ int n = 1 << ((ai) & 3); \
344
+ READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, n); \
345
+ switch ((ai) & 3) { \
346
+ case 0: { \
347
+ val = cb->u8; \
348
+ break; \
349
+ } \
350
+ case 1: { \
351
+ val = _msgpack_be16(cb->u16); \
352
+ break; \
353
+ } \
354
+ case 2: { \
355
+ val = _msgpack_be32(cb->u32); \
356
+ break; \
357
+ } \
358
+ case 3: { \
359
+ val = _msgpack_be64(cb->u64); \
360
+ break; \
361
+ } \
362
+ } \
363
+ }
364
+
365
+
366
+ /* All the cases with an immediate value in the AI */
367
+ #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)
368
+ /* The case with additional information */
369
+ #define CASE_AI(n) case ((n*8) + 6)
370
+ /* The case with the reserved and indefinite ai values */
371
+ #define CASE_INDEF(n) case ((n*8) + 7)
372
+
373
+ static int read_primitive(msgpack_unpacker_t* uk)
374
+ {
375
+ if(uk->reading_raw_remaining > 0) {
376
+ // printf("calling read_raw_body_cont, %d\n", __LINE__); // Debug. 陈欣
377
+ return read_raw_body_cont(uk, uk->textflag);
378
+ }
379
+
380
+ int ib = get_head_byte(uk);
381
+ if (ib < 0) {
382
+ return ib;
383
+ }
384
+
385
+ int ai = IB_AI(ib);
386
+ uint64_t val = ai;
387
+
388
+ switch (ib >> 2) {
389
+ CASE_IMM(MT_UNSIGNED): // Positive Fixnum
390
+ return object_complete(uk, INT2FIX(ai));
391
+ CASE_AI(MT_UNSIGNED):
392
+ READ_VAL(uk, ai, val);
393
+ return object_complete(uk, rb_ull2inum(val));
394
+ CASE_IMM(MT_NEGATIVE): // Negative Fixnum
395
+ return object_complete(uk, INT2FIX(~ai));
396
+ CASE_AI(MT_NEGATIVE):
397
+ READ_VAL(uk, ai, val);
398
+ return object_complete(uk,
399
+ (val & 0x8000000000000000
400
+ ? rb_funcall(rb_ull2inum(val), rb_intern("~"), 0)
401
+ : rb_ll2inum(~val)));
402
+ CASE_AI(MT_BYTES): CASE_AI(MT_TEXT):
403
+ READ_VAL(uk, ai, val);
404
+ CASE_IMM(MT_BYTES): // byte string
405
+ CASE_IMM(MT_TEXT): // text string
406
+ if (val == 0) {
407
+ return object_complete_string(uk, rb_str_buf_new(0), ib & IB_TEXTFLAG);
408
+ }
409
+ uk->reading_raw_remaining = val; /* TODO: range checks on val here and below */
410
+ // printf("calling read_raw_body_begin, %d\n", __LINE__); // Debug. 陈欣
411
+ return read_raw_body_begin(uk, ib & IB_TEXTFLAG);
412
+ CASE_AI(MT_ARRAY):
413
+ READ_VAL(uk, ai, val);
414
+ CASE_IMM(MT_ARRAY): // array
415
+ if (val == 0) {
416
+ return object_complete(uk, rb_ary_new());
417
+ }
418
+ return _msgpack_unpacker_stack_push(uk, STACK_TYPE_ARRAY, val, rb_ary_new2(SANE_PREALLOCATE(val)));
419
+ CASE_AI(MT_MAP):
420
+ READ_VAL(uk, ai, val);
421
+ CASE_IMM(MT_MAP): // map
422
+ if (val == 0) {
423
+ return object_complete(uk, rb_hash_new());
424
+ }
425
+ return _msgpack_unpacker_stack_push(uk, STACK_TYPE_MAP_KEY, val*2, rb_hash_new());
426
+ CASE_AI(MT_TAG):
427
+ READ_VAL(uk, ai, val);
428
+ CASE_IMM(MT_TAG): // tag
429
+ return _msgpack_unpacker_stack_push_tag(uk, STACK_TYPE_TAG, 1, Qnil, val);
430
+ case MT_PRIM*8+5:
431
+ switch(ai) {
432
+ case VAL_NIL: // nil
433
+ return object_complete(uk, Qnil);
434
+ case VAL_FALSE: // false
435
+ return object_complete(uk, Qfalse);
436
+ case VAL_TRUE: // true
437
+ return object_complete(uk, Qtrue);
438
+ }
439
+ /* fall through */
440
+ case MT_PRIM*8: case MT_PRIM*8+1: case MT_PRIM*8+2: case MT_PRIM*8+3: case MT_PRIM*8+4:
441
+ return object_complete(uk, rb_struct_new(rb_cCBOR_Simple, INT2FIX(val)));
442
+ CASE_AI(MT_PRIM):
443
+ READ_VAL(uk, ai, val);
444
+ switch (ai) {
445
+ case AI_2: { // half
446
+ int exp = (val >> 10) & 0x1f;
447
+ int mant = val & 0x3ff;
448
+ double res;
449
+ if (exp == 0) res = ldexp(mant, -24);
450
+ else if (exp != 31) res = ldexp11(mant + 1024, exp - 25);
451
+ else res = mant == 0 ? INFINITY : NAN;
452
+ return object_complete(uk, rb_float_new(val & 0x8000 ? -res : res));
453
+ }
454
+ case AI_4: // float
455
+ {
456
+ union {
457
+ uint32_t u32;
458
+ float f;
459
+ } castbuf = { (uint32_t)val };
460
+ return object_complete(uk, rb_float_new(castbuf.f));
461
+ }
462
+ case AI_8: // double
463
+ {
464
+ union {
465
+ uint64_t u64;
466
+ double d;
467
+ } castbuf = { val };
468
+ return object_complete(uk, rb_float_new(castbuf.d));
469
+ }
470
+ default:
471
+ return object_complete(uk, rb_struct_new(rb_cCBOR_Simple, INT2FIX(val)));
472
+ }
473
+ CASE_INDEF(MT_BYTES): CASE_INDEF(MT_TEXT): /* handle string */
474
+ if (ai == AI_INDEF)
475
+ return _msgpack_unpacker_stack_push(uk, STACK_TYPE_STRING_INDEF, ib & IB_TEXTFLAG,
476
+ object_string_encoding_set(rb_str_buf_new(0),
477
+ ib & IB_TEXTFLAG));
478
+ /* fall through */
479
+ CASE_INDEF(MT_ARRAY):
480
+ if (ai == AI_INDEF)
481
+ return _msgpack_unpacker_stack_push(uk, STACK_TYPE_ARRAY_INDEF, 0, rb_ary_new2(0));
482
+ /* fall through */
483
+ CASE_INDEF(MT_MAP):
484
+ if (ai == AI_INDEF)
485
+ return _msgpack_unpacker_stack_push(uk, STACK_TYPE_MAP_KEY_INDEF, 0, rb_hash_new());
486
+ /* fall through */
487
+ CASE_INDEF(MT_PRIM):
488
+ if (ai == AI_INDEF)
489
+ return PRIMITIVE_BREAK;
490
+ /* fall through */
491
+ }
492
+ return PRIMITIVE_INVALID_BYTE;
493
+ }
494
+
495
+
496
+ int msgpack_unpacker_read_container_header(msgpack_unpacker_t* uk, uint64_t* result_size, int ib)
497
+ {
498
+ int b = get_head_byte(uk);
499
+ if(b < 0) {
500
+ return b;
501
+ }
502
+
503
+ if(ib <= b && b < (ib + AI_1)) {
504
+ *result_size = IB_AI(b);
505
+ } else if((b & ~0x3) == (ib + AI_1)) {
506
+ uint64_t val;
507
+ READ_VAL(uk, b, val);
508
+ *result_size = val;
509
+ } else {
510
+ return PRIMITIVE_UNEXPECTED_TYPE; /* including INDEF! */
511
+ }
512
+
513
+ reset_head_byte(uk);
514
+ return 0;
515
+ }
516
+
517
+
518
+ int msgpack_unpacker_read_array_header(msgpack_unpacker_t* uk, uint64_t* result_size) {
519
+ return msgpack_unpacker_read_container_header(uk, result_size, IB_ARRAY);
520
+ }
521
+
522
+ int msgpack_unpacker_read_map_header(msgpack_unpacker_t* uk, uint64_t* result_size) {
523
+ return msgpack_unpacker_read_container_header(uk, result_size, IB_MAP);
524
+ }
525
+
526
+ static VALUE msgpack_unpacker_process_tag(uint64_t tag, VALUE v) {
527
+ VALUE res = v;
528
+ switch (tag) {
529
+ case TAG_TIME_EPOCH: {
530
+ return rb_funcall(rb_cTime, rb_intern("at"), 1, v);
531
+ }
532
+ case TAG_RE: {
533
+ return rb_funcall(rb_cRegexp, rb_intern("new"), 1, v);
534
+ }
535
+ case TAG_URI: {
536
+ if (!rb_const_defined(rb_cObject, rb_intern("URI")))
537
+ goto unknown_tag;
538
+ return rb_funcall(rb_const_get(rb_cObject, rb_intern("URI")),
539
+ rb_intern("parse"), 1, v);
540
+ }
541
+ case TAG_BIGNUM_NEG:
542
+ case TAG_BIGNUM:
543
+ /* check object is a byte string */
544
+ if (rb_type(v) != T_STRING)
545
+ break; /* XXX: really should error out here */
546
+ #ifdef COMPAT_HAVE_ENCODING
547
+ if (ENCODING_GET(v) != s_enc_ascii8bit)
548
+ break; /* XXX: really should error out here */
549
+ #endif
550
+ {
551
+ char *sp = RSTRING_PTR(v);
552
+ size_t slen = RSTRING_LEN(v);
553
+ while (slen && *sp == 0) {
554
+ slen--;
555
+ sp++;
556
+ }
557
+
558
+ #ifdef HAVE_RB_INTEGER_UNPACK
559
+
560
+ res = rb_integer_unpack(sp, slen, 1, 0, INTEGER_PACK_BIG_ENDIAN);
561
+ /* (const void *words, size_t numwords, size_t wordsize, size_t nails, int flags); */
562
+
563
+ #else
564
+
565
+ #ifndef CANT_DO_BIGNUMS_FAST_ON_THIS_PLATFORM
566
+ int ndig = (slen + SIZEOF_BDIGITS - 1)/SIZEOF_BDIGITS;
567
+ res = rb_big_new(ndig, 1);
568
+ /* compute number RSTRING_PTR(v) */
569
+ if (ndig) {
570
+ BDIGIT *ds = RBIGNUM_DIGITS(res);
571
+ int missbytes = ndig*SIZEOF_BDIGITS - slen; /* 0..SIZEOF_BDIGITS - 1 */
572
+ union {
573
+ char msdig_str[SIZEOF_BDIGITS];
574
+ BDIGIT msdig_bd;
575
+ } u;
576
+ u.msdig_bd = 0;
577
+ memcpy(u.msdig_str + missbytes, sp, SIZEOF_BDIGITS - missbytes);
578
+ ds[ndig-1] = NTOHBDIGIT(u.msdig_bd);
579
+ sp += SIZEOF_BDIGITS - missbytes;
580
+ while (--ndig > 0) {
581
+ memcpy(u.msdig_str, sp, SIZEOF_BDIGITS);
582
+ ds[ndig-1] = NTOHBDIGIT(u.msdig_bd);
583
+ sp += SIZEOF_BDIGITS;
584
+ }
585
+ }
586
+ #else
587
+ {
588
+ /* This is a slow workaround only... But a working one. */
589
+ char *hex = ALLOC_N(char, 2 * slen + 1);
590
+ char *p = hex;
591
+ while (slen) {
592
+ sprintf(p, "%02x", *sp++ & 0xFF);
593
+ p += 2;
594
+ slen--;
595
+ }
596
+ *p = 0;
597
+ res = rb_cstr2inum(hex, 16);
598
+ xfree(hex);
599
+ }
600
+ #endif
601
+ #endif
602
+ if (tag == TAG_BIGNUM) /* non-negative */
603
+ #ifndef CANT_DO_BIGNUMS_FAST_ON_THIS_PLATFORM
604
+ return rb_big_norm(res);
605
+ #else
606
+ return res;
607
+ #endif
608
+ else
609
+ return rb_funcall(res, rb_intern("~"), 0); /* should be rb_big_neg(), but that is static. */
610
+ }
611
+ }
612
+ unknown_tag:
613
+ /* common return for unknown tags */
614
+ return rb_struct_new(rb_cCBOR_Tagged, rb_ull2inum(tag), v);
615
+ }
616
+
617
+ int msgpack_unpacker_read(msgpack_unpacker_t* uk, size_t target_stack_depth)
618
+ {
619
+ while(true) {
620
+ // printf("calling read_primitive, %d\n", __LINE__); // Debug. 陈欣
621
+ int r = read_primitive(uk);
622
+ if(r < 0) {
623
+ return r;
624
+ }
625
+ if(r == PRIMITIVE_CONTAINER_START) {
626
+ continue;
627
+ }
628
+ /* PRIMITIVE_OBJECT_COMPLETE */
629
+
630
+ if(msgpack_unpacker_stack_is_empty(uk)) {
631
+ if (r == PRIMITIVE_BREAK)
632
+ return PRIMITIVE_INVALID_BYTE;
633
+ return PRIMITIVE_OBJECT_COMPLETE;
634
+ }
635
+
636
+ container_completed:
637
+ {
638
+ msgpack_unpacker_stack_t* top = _msgpack_unpacker_stack_top(uk);
639
+ if (top->type <= STACK_TYPE_MAP_VALUE_INDEF && r == PRIMITIVE_BREAK)
640
+ return PRIMITIVE_INVALID_BYTE;
641
+ switch(top->type) {
642
+ case STACK_TYPE_ARRAY:
643
+ rb_ary_push(top->object, uk->last_object);
644
+ break;
645
+ case STACK_TYPE_MAP_KEY:
646
+ top->key = uk->last_object;
647
+ top->type = STACK_TYPE_MAP_VALUE;
648
+ break;
649
+ case STACK_TYPE_MAP_VALUE:
650
+ rb_hash_aset(top->object, top->key, uk->last_object);
651
+ top->type = STACK_TYPE_MAP_KEY;
652
+ break;
653
+ case STACK_TYPE_TAG:
654
+ object_complete(uk, msgpack_unpacker_process_tag(top->tag, uk->last_object));
655
+ goto done;
656
+
657
+ case STACK_TYPE_ARRAY_INDEF:
658
+ if (r == PRIMITIVE_BREAK)
659
+ goto complete;
660
+ rb_ary_push(top->object, uk->last_object);
661
+ continue;
662
+ case STACK_TYPE_MAP_KEY_INDEF:
663
+ if (r == PRIMITIVE_BREAK)
664
+ goto complete;
665
+ top->key = uk->last_object;
666
+ top->type = STACK_TYPE_MAP_VALUE_INDEF;
667
+ continue;
668
+ case STACK_TYPE_MAP_VALUE_INDEF:
669
+ rb_hash_aset(top->object, top->key, uk->last_object);
670
+ top->type = STACK_TYPE_MAP_KEY_INDEF;
671
+ continue;
672
+ case STACK_TYPE_STRING_INDEF:
673
+ if (r == PRIMITIVE_BREAK) {
674
+ object_complete_string(uk, top->object, (int)top->count); /* use count as textflag */
675
+ goto done;
676
+ }
677
+ if (!RB_TYPE_P(uk->last_object, T_STRING))
678
+ return PRIMITIVE_INVALID_BYTE;
679
+ #ifdef COMPAT_HAVE_ENCODING /* XXX */
680
+ if (ENCODING_GET(top->object) != ENCODING_GET(uk->last_object))
681
+ return PRIMITIVE_INVALID_BYTE;
682
+ #endif
683
+ rb_str_append(top->object, uk->last_object);
684
+ continue;
685
+ }
686
+ size_t count = --top->count;
687
+
688
+ if(count == 0) {
689
+ complete:;
690
+ object_complete(uk, top->object);
691
+ done:;
692
+ if(msgpack_unpacker_stack_pop(uk) <= target_stack_depth) {
693
+ return PRIMITIVE_OBJECT_COMPLETE;
694
+ }
695
+ goto container_completed;
696
+ }
697
+ }
698
+ }
699
+ }
700
+
701
+ int msgpack_unpacker_skip(msgpack_unpacker_t* uk, size_t target_stack_depth)
702
+ {
703
+ while(true) {
704
+ int r = read_primitive(uk);
705
+ if(r < 0) {
706
+ return r;
707
+ }
708
+ if(r == PRIMITIVE_CONTAINER_START) {
709
+ continue;
710
+ }
711
+ /* PRIMITIVE_OBJECT_COMPLETE */
712
+
713
+ if(msgpack_unpacker_stack_is_empty(uk)) {
714
+ return PRIMITIVE_OBJECT_COMPLETE;
715
+ }
716
+
717
+ container_completed:
718
+ {
719
+ msgpack_unpacker_stack_t* top = _msgpack_unpacker_stack_top(uk);
720
+
721
+ /* this section optimized out */
722
+ // TODO object_complete still creates objects which should be optimized out
723
+ /* XXX: check INDEF! */
724
+
725
+ size_t count = --top->count;
726
+
727
+ if(count == 0) {
728
+ object_complete(uk, Qnil);
729
+ if(msgpack_unpacker_stack_pop(uk) <= target_stack_depth) {
730
+ return PRIMITIVE_OBJECT_COMPLETE;
731
+ }
732
+ goto container_completed;
733
+ }
734
+ }
735
+ }
736
+ }
737
+
738
+ /* dead code, but keep it for comparison purposes */
739
+
740
+ static enum msgpack_unpacker_object_type msgpack_unpacker_object_types_per_mt[] = {
741
+ TYPE_INTEGER, TYPE_INTEGER,
742
+ TYPE_RAW, TYPE_RAW, /* XXX */
743
+ TYPE_ARRAY, TYPE_MAP,
744
+ TYPE_INTEGER, /* XXX */
745
+ TYPE_NIL /* see below: */
746
+ };
747
+
748
+ static enum msgpack_unpacker_object_type msgpack_unpacker_object_types_per_ai[] = {
749
+ PRIMITIVE_INVALID_BYTE, PRIMITIVE_INVALID_BYTE, PRIMITIVE_INVALID_BYTE, PRIMITIVE_INVALID_BYTE,
750
+ PRIMITIVE_INVALID_BYTE, PRIMITIVE_INVALID_BYTE, PRIMITIVE_INVALID_BYTE, PRIMITIVE_INVALID_BYTE,
751
+ PRIMITIVE_INVALID_BYTE, PRIMITIVE_INVALID_BYTE, PRIMITIVE_INVALID_BYTE, PRIMITIVE_INVALID_BYTE,
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
+ TYPE_BOOLEAN, TYPE_BOOLEAN, TYPE_NIL, PRIMITIVE_INVALID_BYTE, /* XXX */
755
+ PRIMITIVE_INVALID_BYTE, TYPE_FLOAT, TYPE_FLOAT, TYPE_FLOAT,
756
+ PRIMITIVE_INVALID_BYTE, PRIMITIVE_INVALID_BYTE, PRIMITIVE_INVALID_BYTE, PRIMITIVE_INVALID_BYTE,
757
+ };
758
+
759
+ int msgpack_unpacker_peek_next_object_type(msgpack_unpacker_t* uk)
760
+ {
761
+ int ib = get_head_byte(uk);
762
+ if (ib < 0) {
763
+ return ib;
764
+ }
765
+
766
+ int t = msgpack_unpacker_object_types_per_mt[IB_MT(ib)];
767
+ if (t == TYPE_NIL) {
768
+ t = msgpack_unpacker_object_types_per_ai[IB_AI(ib)];
769
+ }
770
+ return t;
771
+ }
772
+
773
+ int msgpack_unpacker_skip_nil(msgpack_unpacker_t* uk)
774
+ {
775
+ int b = get_head_byte(uk);
776
+ if(b < 0) {
777
+ return b;
778
+ }
779
+ if (b == IB_NIL) {
780
+ return 1;
781
+ }
782
+ return 0;
783
+ }
784
+