cbor 0.5.6.2

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