cbor 0.5.6.2

Sign up to get free protection for your applications and to get access to all the features.
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
+