msgpack-ably 0.5.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +20 -0
  3. data/.travis.yml +26 -0
  4. data/ChangeLog +101 -0
  5. data/README.rdoc +129 -0
  6. data/Rakefile +110 -0
  7. data/doclib/msgpack.rb +77 -0
  8. data/doclib/msgpack/buffer.rb +193 -0
  9. data/doclib/msgpack/core_ext.rb +101 -0
  10. data/doclib/msgpack/error.rb +14 -0
  11. data/doclib/msgpack/packer.rb +134 -0
  12. data/doclib/msgpack/unpacker.rb +146 -0
  13. data/ext/msgpack/buffer.c +678 -0
  14. data/ext/msgpack/buffer.h +441 -0
  15. data/ext/msgpack/buffer_class.c +507 -0
  16. data/ext/msgpack/buffer_class.h +32 -0
  17. data/ext/msgpack/compat.h +113 -0
  18. data/ext/msgpack/core_ext.c +129 -0
  19. data/ext/msgpack/core_ext.h +26 -0
  20. data/ext/msgpack/extconf.rb +28 -0
  21. data/ext/msgpack/packer.c +168 -0
  22. data/ext/msgpack/packer.h +429 -0
  23. data/ext/msgpack/packer_class.c +302 -0
  24. data/ext/msgpack/packer_class.h +30 -0
  25. data/ext/msgpack/rbinit.c +33 -0
  26. data/ext/msgpack/rmem.c +94 -0
  27. data/ext/msgpack/rmem.h +109 -0
  28. data/ext/msgpack/sysdep.h +115 -0
  29. data/ext/msgpack/sysdep_endian.h +50 -0
  30. data/ext/msgpack/sysdep_types.h +46 -0
  31. data/ext/msgpack/unpacker.c +781 -0
  32. data/ext/msgpack/unpacker.h +122 -0
  33. data/ext/msgpack/unpacker_class.c +405 -0
  34. data/ext/msgpack/unpacker_class.h +32 -0
  35. data/lib/msgpack.rb +6 -0
  36. data/lib/msgpack/version.rb +3 -0
  37. data/msgpack.gemspec +26 -0
  38. data/msgpack.org.md +49 -0
  39. data/spec/cases.json +1 -0
  40. data/spec/cases.msg +0 -0
  41. data/spec/cases_compact.msg +0 -0
  42. data/spec/cases_spec.rb +39 -0
  43. data/spec/cruby/buffer_io_spec.rb +256 -0
  44. data/spec/cruby/buffer_packer.rb +29 -0
  45. data/spec/cruby/buffer_spec.rb +572 -0
  46. data/spec/cruby/buffer_unpacker.rb +19 -0
  47. data/spec/format_spec.rb +256 -0
  48. data/spec/packer_spec.rb +120 -0
  49. data/spec/random_compat.rb +24 -0
  50. data/spec/spec_helper.rb +21 -0
  51. data/spec/unpacker_spec.rb +305 -0
  52. metadata +195 -0
@@ -0,0 +1,781 @@
1
+ /*
2
+ * MessagePack for Ruby
3
+ *
4
+ * Copyright (C) 2008-2013 Sadayuki Furuhashi
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */
18
+
19
+ #include "unpacker.h"
20
+ #include "rmem.h"
21
+
22
+ #if !defined(DISABLE_RMEM) && !defined(DISABLE_UNPACKER_STACK_RMEM) && \
23
+ MSGPACK_UNPACKER_STACK_CAPACITY * MSGPACK_UNPACKER_STACK_SIZE <= MSGPACK_RMEM_PAGE_SIZE
24
+ #define UNPACKER_STACK_RMEM
25
+ #endif
26
+
27
+ #ifdef UNPACKER_STACK_RMEM
28
+ static msgpack_rmem_t s_stack_rmem;
29
+ #endif
30
+
31
+ #ifdef COMPAT_HAVE_ENCODING /* see compat.h*/
32
+ static int s_enc_utf8;
33
+ static int s_enc_ascii_8bit;
34
+ #endif
35
+
36
+ void msgpack_unpacker_static_init()
37
+ {
38
+ #ifdef UNPACKER_STACK_RMEM
39
+ msgpack_rmem_init(&s_stack_rmem);
40
+ #endif
41
+
42
+ #ifdef COMPAT_HAVE_ENCODING
43
+ s_enc_utf8 = rb_utf8_encindex();
44
+ s_enc_ascii_8bit = rb_ascii8bit_encindex();
45
+ #endif
46
+ }
47
+
48
+ void msgpack_unpacker_static_destroy()
49
+ {
50
+ #ifdef UNPACKER_STACK_RMEM
51
+ msgpack_rmem_destroy(&s_stack_rmem);
52
+ #endif
53
+ }
54
+
55
+ #define HEAD_BYTE_REQUIRED 0xc1
56
+
57
+ void msgpack_unpacker_init(msgpack_unpacker_t* uk)
58
+ {
59
+ memset(uk, 0, sizeof(msgpack_unpacker_t));
60
+
61
+ msgpack_buffer_init(UNPACKER_BUFFER_(uk));
62
+
63
+ uk->head_byte = HEAD_BYTE_REQUIRED;
64
+
65
+ uk->last_object = Qnil;
66
+ uk->reading_raw = Qnil;
67
+
68
+ #ifdef UNPACKER_STACK_RMEM
69
+ uk->stack = msgpack_rmem_alloc(&s_stack_rmem);
70
+ /*memset(uk->stack, 0, MSGPACK_UNPACKER_STACK_CAPACITY);*/
71
+ #else
72
+ /*uk->stack = calloc(MSGPACK_UNPACKER_STACK_CAPACITY, sizeof(msgpack_unpacker_stack_t));*/
73
+ uk->stack = malloc(MSGPACK_UNPACKER_STACK_CAPACITY * sizeof(msgpack_unpacker_stack_t));
74
+ #endif
75
+ uk->stack_capacity = MSGPACK_UNPACKER_STACK_CAPACITY;
76
+ }
77
+
78
+ void msgpack_unpacker_destroy(msgpack_unpacker_t* uk)
79
+ {
80
+ #ifdef UNPACKER_STACK_RMEM
81
+ msgpack_rmem_free(&s_stack_rmem, uk->stack);
82
+ #else
83
+ free(uk->stack);
84
+ #endif
85
+
86
+ msgpack_buffer_destroy(UNPACKER_BUFFER_(uk));
87
+ }
88
+
89
+ void msgpack_unpacker_mark(msgpack_unpacker_t* uk)
90
+ {
91
+ rb_gc_mark(uk->last_object);
92
+ rb_gc_mark(uk->reading_raw);
93
+
94
+ msgpack_unpacker_stack_t* s = uk->stack;
95
+ msgpack_unpacker_stack_t* send = uk->stack + uk->stack_depth;
96
+ for(; s < send; s++) {
97
+ rb_gc_mark(s->object);
98
+ rb_gc_mark(s->key);
99
+ }
100
+
101
+ /* See MessagePack_Buffer_wrap */
102
+ /* msgpack_buffer_mark(UNPACKER_BUFFER_(uk)); */
103
+ rb_gc_mark(uk->buffer_ref);
104
+ }
105
+
106
+ void msgpack_unpacker_reset(msgpack_unpacker_t* uk)
107
+ {
108
+ msgpack_buffer_clear(UNPACKER_BUFFER_(uk));
109
+
110
+ uk->head_byte = HEAD_BYTE_REQUIRED;
111
+
112
+ /*memset(uk->stack, 0, sizeof(msgpack_unpacker_t) * uk->stack_depth);*/
113
+ uk->stack_depth = 0;
114
+
115
+ uk->last_object = Qnil;
116
+ uk->reading_raw = Qnil;
117
+ uk->reading_raw_remaining = 0;
118
+ }
119
+
120
+
121
+ /* head byte functions */
122
+ static int read_head_byte(msgpack_unpacker_t* uk)
123
+ {
124
+ int r = msgpack_buffer_read_1(UNPACKER_BUFFER_(uk));
125
+ if(r == -1) {
126
+ return PRIMITIVE_EOF;
127
+ }
128
+ return uk->head_byte = r;
129
+ }
130
+
131
+ static inline int get_head_byte(msgpack_unpacker_t* uk)
132
+ {
133
+ int b = uk->head_byte;
134
+ if(b == HEAD_BYTE_REQUIRED) {
135
+ b = read_head_byte(uk);
136
+ }
137
+ return b;
138
+ }
139
+
140
+ static inline void reset_head_byte(msgpack_unpacker_t* uk)
141
+ {
142
+ uk->head_byte = HEAD_BYTE_REQUIRED;
143
+ }
144
+
145
+ static inline int object_complete(msgpack_unpacker_t* uk, VALUE object)
146
+ {
147
+ uk->last_object = object;
148
+ reset_head_byte(uk);
149
+ return PRIMITIVE_OBJECT_COMPLETE;
150
+ }
151
+
152
+ static inline int object_complete_string(msgpack_unpacker_t* uk, VALUE str)
153
+ {
154
+ #ifdef COMPAT_HAVE_ENCODING
155
+ ENCODING_SET(str, s_enc_utf8);
156
+ #endif
157
+ return object_complete(uk, str);
158
+ }
159
+
160
+ static inline int object_complete_byte_array(msgpack_unpacker_t* uk, VALUE str)
161
+ {
162
+ #ifdef COMPAT_HAVE_ENCODING
163
+ // TODO ruby 2.0 has String#b method
164
+ ENCODING_SET(str, s_enc_ascii_8bit);
165
+ #endif
166
+ return object_complete(uk, str);
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(msgpack_unpacker_t* uk, enum stack_type_t type, size_t count, VALUE object)
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
+
189
+ uk->stack_depth++;
190
+ return PRIMITIVE_CONTAINER_START;
191
+ }
192
+
193
+ static inline VALUE msgpack_unpacker_stack_pop(msgpack_unpacker_t* uk)
194
+ {
195
+ return --uk->stack_depth;
196
+ }
197
+
198
+ static inline bool msgpack_unpacker_stack_is_empty(msgpack_unpacker_t* uk)
199
+ {
200
+ return uk->stack_depth == 0;
201
+ }
202
+
203
+ #ifdef USE_CASE_RANGE
204
+
205
+ #define SWITCH_RANGE_BEGIN(BYTE) { switch(BYTE) {
206
+ #define SWITCH_RANGE(BYTE, FROM, TO) } case FROM ... TO: {
207
+ #define SWITCH_RANGE_DEFAULT } default: {
208
+ #define SWITCH_RANGE_END } }
209
+
210
+ #else
211
+
212
+ #define SWITCH_RANGE_BEGIN(BYTE) { if(0) {
213
+ #define SWITCH_RANGE(BYTE, FROM, TO) } else if(FROM <= (BYTE) && (BYTE) <= TO) {
214
+ #define SWITCH_RANGE_DEFAULT } else {
215
+ #define SWITCH_RANGE_END } }
216
+
217
+ #endif
218
+
219
+
220
+ #define READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, n) \
221
+ union msgpack_buffer_cast_block_t* cb = msgpack_buffer_read_cast_block(UNPACKER_BUFFER_(uk), n); \
222
+ if(cb == NULL) { \
223
+ return PRIMITIVE_EOF; \
224
+ }
225
+
226
+ static inline bool is_reading_map_key(msgpack_unpacker_t* uk)
227
+ {
228
+ if(uk->stack_depth > 0) {
229
+ msgpack_unpacker_stack_t* top = _msgpack_unpacker_stack_top(uk);
230
+ if(top->type == STACK_TYPE_MAP_KEY) {
231
+ return true;
232
+ }
233
+ }
234
+ return false;
235
+ }
236
+
237
+ static int read_raw_body_cont(msgpack_unpacker_t* uk)
238
+ {
239
+ size_t length = uk->reading_raw_remaining;
240
+
241
+ if(uk->reading_raw == Qnil) {
242
+ uk->reading_raw = rb_str_buf_new(length);
243
+ }
244
+
245
+ do {
246
+ size_t n = msgpack_buffer_read_to_string(UNPACKER_BUFFER_(uk), uk->reading_raw, length);
247
+ if(n == 0) {
248
+ return PRIMITIVE_EOF;
249
+ }
250
+ /* update reading_raw_remaining everytime because
251
+ * msgpack_buffer_read_to_string raises IOError */
252
+ uk->reading_raw_remaining = length = length - n;
253
+ } while(length > 0);
254
+
255
+ object_complete_string(uk, uk->reading_raw);
256
+ uk->reading_raw = Qnil;
257
+ return PRIMITIVE_OBJECT_COMPLETE;
258
+ }
259
+
260
+ static inline int read_raw_body_begin(msgpack_unpacker_t* uk, bool str)
261
+ {
262
+ /* assuming uk->reading_raw == Qnil */
263
+
264
+ /* try optimized read */
265
+ size_t length = uk->reading_raw_remaining;
266
+ if(length <= msgpack_buffer_top_readable_size(UNPACKER_BUFFER_(uk))) {
267
+ /* don't use zerocopy for hash keys but get a frozen string directly
268
+ * because rb_hash_aset freezes keys and it causes copying */
269
+ bool will_freeze = is_reading_map_key(uk);
270
+ VALUE string = msgpack_buffer_read_top_as_string(UNPACKER_BUFFER_(uk), length, will_freeze);
271
+ if(str == true) {
272
+ object_complete_string(uk, string);
273
+ } else {
274
+ object_complete_byte_array(uk, string);
275
+ }
276
+ if(will_freeze) {
277
+ rb_obj_freeze(string);
278
+ }
279
+ uk->reading_raw_remaining = 0;
280
+ return PRIMITIVE_OBJECT_COMPLETE;
281
+ }
282
+
283
+ return read_raw_body_cont(uk);
284
+ }
285
+
286
+ static int read_primitive(msgpack_unpacker_t* uk)
287
+ {
288
+ if(uk->reading_raw_remaining > 0) {
289
+ return read_raw_body_cont(uk);
290
+ }
291
+
292
+ int b = get_head_byte(uk);
293
+ if(b < 0) {
294
+ return b;
295
+ }
296
+
297
+ SWITCH_RANGE_BEGIN(b)
298
+ SWITCH_RANGE(b, 0x00, 0x7f) // Positive Fixnum
299
+ return object_complete(uk, INT2NUM(b));
300
+
301
+ SWITCH_RANGE(b, 0xe0, 0xff) // Negative Fixnum
302
+ return object_complete(uk, INT2NUM((int8_t)b));
303
+
304
+ SWITCH_RANGE(b, 0xa0, 0xbf) // FixRaw / fixstr
305
+ int count = b & 0x1f;
306
+ if(count == 0) {
307
+ return object_complete_string(uk, rb_str_buf_new(0));
308
+ }
309
+ /* read_raw_body_begin sets uk->reading_raw */
310
+ uk->reading_raw_remaining = count;
311
+ return read_raw_body_begin(uk, true);
312
+
313
+ SWITCH_RANGE(b, 0x90, 0x9f) // FixArray
314
+ int count = b & 0x0f;
315
+ if(count == 0) {
316
+ return object_complete(uk, rb_ary_new());
317
+ }
318
+ return _msgpack_unpacker_stack_push(uk, STACK_TYPE_ARRAY, count, rb_ary_new2(count));
319
+
320
+ SWITCH_RANGE(b, 0x80, 0x8f) // FixMap
321
+ int count = b & 0x0f;
322
+ if(count == 0) {
323
+ return object_complete(uk, rb_hash_new());
324
+ }
325
+ return _msgpack_unpacker_stack_push(uk, STACK_TYPE_MAP_KEY, count*2, rb_hash_new());
326
+
327
+ SWITCH_RANGE(b, 0xc0, 0xdf) // Variable
328
+ switch(b) {
329
+ case 0xc0: // nil
330
+ return object_complete(uk, Qnil);
331
+
332
+ //case 0xc1: // string
333
+
334
+ case 0xc2: // false
335
+ return object_complete(uk, Qfalse);
336
+
337
+ case 0xc3: // true
338
+ return object_complete(uk, Qtrue);
339
+
340
+ //case 0xc7: // ext 8
341
+ //case 0xc8: // ext 16
342
+ //case 0xc9: // ext 32
343
+
344
+ case 0xca: // float
345
+ {
346
+ READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 4);
347
+ cb->u32 = _msgpack_be_float(cb->u32);
348
+ return object_complete(uk, rb_float_new(cb->f));
349
+ }
350
+
351
+ case 0xcb: // double
352
+ {
353
+ READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 8);
354
+ cb->u64 = _msgpack_be_double(cb->u64);
355
+ return object_complete(uk, rb_float_new(cb->d));
356
+ }
357
+
358
+ case 0xcc: // unsigned int 8
359
+ {
360
+ READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 1);
361
+ uint8_t u8 = cb->u8;
362
+ return object_complete(uk, INT2NUM((int)u8));
363
+ }
364
+
365
+ case 0xcd: // unsigned int 16
366
+ {
367
+ READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 2);
368
+ uint16_t u16 = _msgpack_be16(cb->u16);
369
+ return object_complete(uk, INT2NUM((int)u16));
370
+ }
371
+
372
+ case 0xce: // unsigned int 32
373
+ {
374
+ READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 4);
375
+ uint32_t u32 = _msgpack_be32(cb->u32);
376
+ return object_complete(uk, ULONG2NUM((unsigned long)u32));
377
+ }
378
+
379
+ case 0xcf: // unsigned int 64
380
+ {
381
+ READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 8);
382
+ uint64_t u64 = _msgpack_be64(cb->u64);
383
+ return object_complete(uk, rb_ull2inum(u64));
384
+ }
385
+
386
+ case 0xd0: // signed int 8
387
+ {
388
+ READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 1);
389
+ int8_t i8 = cb->i8;
390
+ return object_complete(uk, INT2NUM((int)i8));
391
+ }
392
+
393
+ case 0xd1: // signed int 16
394
+ {
395
+ READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 2);
396
+ int16_t i16 = _msgpack_be16(cb->i16);
397
+ return object_complete(uk, INT2NUM((int)i16));
398
+ }
399
+
400
+ case 0xd2: // signed int 32
401
+ {
402
+ READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 4);
403
+ int32_t i32 = _msgpack_be32(cb->i32);
404
+ return object_complete(uk, LONG2NUM((long)i32));
405
+ }
406
+
407
+ case 0xd3: // signed int 64
408
+ {
409
+ READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 8);
410
+ int64_t i64 = _msgpack_be64(cb->i64);
411
+ return object_complete(uk, rb_ll2inum(i64));
412
+ }
413
+
414
+ //case 0xd4: // fixext 1
415
+ //case 0xd5: // fixext 2
416
+ //case 0xd6: // fixext 4
417
+ //case 0xd7: // fixext 8
418
+ //case 0xd8: // fixext 16
419
+
420
+ case 0xd9: // raw 8 / str 8
421
+ {
422
+ READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 1);
423
+ uint8_t count = cb->u8;
424
+ if(count == 0) {
425
+ return object_complete_string(uk, rb_str_buf_new(0));
426
+ }
427
+ /* read_raw_body_begin sets uk->reading_raw */
428
+ uk->reading_raw_remaining = count;
429
+ return read_raw_body_begin(uk, true);
430
+ }
431
+
432
+ case 0xda: // raw 16 / str 16
433
+ {
434
+ READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 2);
435
+ uint16_t count = _msgpack_be16(cb->u16);
436
+ if(count == 0) {
437
+ return object_complete_string(uk, rb_str_buf_new(0));
438
+ }
439
+ /* read_raw_body_begin sets uk->reading_raw */
440
+ uk->reading_raw_remaining = count;
441
+ return read_raw_body_begin(uk, true);
442
+ }
443
+
444
+ case 0xdb: // raw 32 / str 32
445
+ {
446
+ READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 4);
447
+ uint32_t count = _msgpack_be32(cb->u32);
448
+ if(count == 0) {
449
+ return object_complete_string(uk, rb_str_buf_new(0));
450
+ }
451
+ /* read_raw_body_begin sets uk->reading_raw */
452
+ uk->reading_raw_remaining = count;
453
+ return read_raw_body_begin(uk, true);
454
+ }
455
+
456
+ case 0xc4: // bin 8
457
+ {
458
+ READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 1);
459
+ uint8_t count = cb->u8;
460
+ if(count == 0) {
461
+ return object_complete_byte_array(uk, rb_str_buf_new(0));
462
+ }
463
+ /* read_raw_body_begin sets uk->reading_raw */
464
+ uk->reading_raw_remaining = count;
465
+ return read_raw_body_begin(uk, false);
466
+ }
467
+
468
+ case 0xc5: // bin 16
469
+ {
470
+ READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 2);
471
+ uint16_t count = _msgpack_be16(cb->u16);
472
+ if(count == 0) {
473
+ return object_complete_byte_array(uk, rb_str_buf_new(0));
474
+ }
475
+ /* read_raw_body_begin sets uk->reading_raw */
476
+ uk->reading_raw_remaining = count;
477
+ return read_raw_body_begin(uk, false);
478
+ }
479
+
480
+ case 0xc6: // bin 32
481
+ {
482
+ READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 4);
483
+ uint32_t count = _msgpack_be32(cb->u32);
484
+ if(count == 0) {
485
+ return object_complete_byte_array(uk, rb_str_buf_new(0));
486
+ }
487
+ /* read_raw_body_begin sets uk->reading_raw */
488
+ uk->reading_raw_remaining = count;
489
+ return read_raw_body_begin(uk, false);
490
+ }
491
+
492
+ case 0xdc: // array 16
493
+ {
494
+ READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 2);
495
+ uint16_t count = _msgpack_be16(cb->u16);
496
+ if(count == 0) {
497
+ return object_complete(uk, rb_ary_new());
498
+ }
499
+ return _msgpack_unpacker_stack_push(uk, STACK_TYPE_ARRAY, count, rb_ary_new2(count));
500
+ }
501
+
502
+ case 0xdd: // array 32
503
+ {
504
+ READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 4);
505
+ uint32_t count = _msgpack_be32(cb->u32);
506
+ if(count == 0) {
507
+ return object_complete(uk, rb_ary_new());
508
+ }
509
+ return _msgpack_unpacker_stack_push(uk, STACK_TYPE_ARRAY, count, rb_ary_new2(count));
510
+ }
511
+
512
+ case 0xde: // map 16
513
+ {
514
+ READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 2);
515
+ uint16_t count = _msgpack_be16(cb->u16);
516
+ if(count == 0) {
517
+ return object_complete(uk, rb_hash_new());
518
+ }
519
+ return _msgpack_unpacker_stack_push(uk, STACK_TYPE_MAP_KEY, count*2, rb_hash_new());
520
+ }
521
+
522
+ case 0xdf: // map 32
523
+ {
524
+ READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 4);
525
+ uint32_t count = _msgpack_be32(cb->u32);
526
+ if(count == 0) {
527
+ return object_complete(uk, rb_hash_new());
528
+ }
529
+ return _msgpack_unpacker_stack_push(uk, STACK_TYPE_MAP_KEY, count*2, rb_hash_new());
530
+ }
531
+
532
+ default:
533
+ return PRIMITIVE_INVALID_BYTE;
534
+ }
535
+
536
+ SWITCH_RANGE_DEFAULT
537
+ return PRIMITIVE_INVALID_BYTE;
538
+
539
+ SWITCH_RANGE_END
540
+ }
541
+
542
+ int msgpack_unpacker_read_array_header(msgpack_unpacker_t* uk, uint32_t* result_size)
543
+ {
544
+ int b = get_head_byte(uk);
545
+ if(b < 0) {
546
+ return b;
547
+ }
548
+
549
+ if(0x90 < b && b < 0x9f) {
550
+ *result_size = b & 0x0f;
551
+
552
+ } else if(b == 0xdc) {
553
+ /* array 16 */
554
+ READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 2);
555
+ *result_size = _msgpack_be16(cb->u16);
556
+
557
+ } else if(b == 0xdd) {
558
+ /* array 32 */
559
+ READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 4);
560
+ *result_size = _msgpack_be32(cb->u32);
561
+
562
+ } else {
563
+ return PRIMITIVE_UNEXPECTED_TYPE;
564
+ }
565
+
566
+ reset_head_byte(uk);
567
+ return 0;
568
+ }
569
+
570
+ int msgpack_unpacker_read_map_header(msgpack_unpacker_t* uk, uint32_t* result_size)
571
+ {
572
+ int b = get_head_byte(uk);
573
+ if(b < 0) {
574
+ return b;
575
+ }
576
+
577
+ if(0x80 < b && b < 0x8f) {
578
+ *result_size = b & 0x0f;
579
+
580
+ } else if(b == 0xde) {
581
+ /* map 16 */
582
+ READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 2);
583
+ *result_size = _msgpack_be16(cb->u16);
584
+
585
+ } else if(b == 0xdf) {
586
+ /* map 32 */
587
+ READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 4);
588
+ *result_size = _msgpack_be32(cb->u32);
589
+
590
+ } else {
591
+ return PRIMITIVE_UNEXPECTED_TYPE;
592
+ }
593
+
594
+ reset_head_byte(uk);
595
+ return 0;
596
+ }
597
+
598
+ int msgpack_unpacker_read(msgpack_unpacker_t* uk, size_t target_stack_depth)
599
+ {
600
+ while(true) {
601
+ int r = read_primitive(uk);
602
+ if(r < 0) {
603
+ return r;
604
+ }
605
+ if(r == PRIMITIVE_CONTAINER_START) {
606
+ continue;
607
+ }
608
+ /* PRIMITIVE_OBJECT_COMPLETE */
609
+
610
+ if(msgpack_unpacker_stack_is_empty(uk)) {
611
+ return PRIMITIVE_OBJECT_COMPLETE;
612
+ }
613
+
614
+ container_completed:
615
+ {
616
+ msgpack_unpacker_stack_t* top = _msgpack_unpacker_stack_top(uk);
617
+ switch(top->type) {
618
+ case STACK_TYPE_ARRAY:
619
+ rb_ary_push(top->object, uk->last_object);
620
+ break;
621
+ case STACK_TYPE_MAP_KEY:
622
+ top->key = uk->last_object;
623
+ top->type = STACK_TYPE_MAP_VALUE;
624
+ break;
625
+ case STACK_TYPE_MAP_VALUE:
626
+ if(uk->symbolize_keys && rb_type(top->key) == T_STRING) {
627
+ /* here uses rb_intern_str instead of rb_intern so that Ruby VM can GC unused symbols */
628
+ #ifdef HAVE_RB_STR_INTERN
629
+ /* rb_str_intern is added since MRI 2.2.0 */
630
+ rb_hash_aset(top->object, rb_str_intern(top->key), uk->last_object);
631
+ #else
632
+ #ifndef HAVE_RB_INTERN_STR
633
+ /* MRI 1.8 doesn't have rb_intern_str or rb_intern2 */
634
+ rb_hash_aset(top->object, ID2SYM(rb_intern(RSTRING_PTR(top->key))), uk->last_object);
635
+ #else
636
+ rb_hash_aset(top->object, ID2SYM(rb_intern_str(top->key)), uk->last_object);
637
+ #endif
638
+ #endif
639
+ } else {
640
+ rb_hash_aset(top->object, top->key, uk->last_object);
641
+ }
642
+ top->type = STACK_TYPE_MAP_KEY;
643
+ break;
644
+ }
645
+ size_t count = --top->count;
646
+
647
+ if(count == 0) {
648
+ object_complete(uk, top->object);
649
+ if(msgpack_unpacker_stack_pop(uk) <= target_stack_depth) {
650
+ return PRIMITIVE_OBJECT_COMPLETE;
651
+ }
652
+ goto container_completed;
653
+ }
654
+ }
655
+ }
656
+ }
657
+
658
+ int msgpack_unpacker_skip(msgpack_unpacker_t* uk, size_t target_stack_depth)
659
+ {
660
+ while(true) {
661
+ int r = read_primitive(uk);
662
+ if(r < 0) {
663
+ return r;
664
+ }
665
+ if(r == PRIMITIVE_CONTAINER_START) {
666
+ continue;
667
+ }
668
+ /* PRIMITIVE_OBJECT_COMPLETE */
669
+
670
+ if(msgpack_unpacker_stack_is_empty(uk)) {
671
+ return PRIMITIVE_OBJECT_COMPLETE;
672
+ }
673
+
674
+ container_completed:
675
+ {
676
+ msgpack_unpacker_stack_t* top = _msgpack_unpacker_stack_top(uk);
677
+
678
+ /* this section optimized out */
679
+ // TODO object_complete still creates objects which should be optimized out
680
+
681
+ size_t count = --top->count;
682
+
683
+ if(count == 0) {
684
+ object_complete(uk, Qnil);
685
+ if(msgpack_unpacker_stack_pop(uk) <= target_stack_depth) {
686
+ return PRIMITIVE_OBJECT_COMPLETE;
687
+ }
688
+ goto container_completed;
689
+ }
690
+ }
691
+ }
692
+ }
693
+
694
+ int msgpack_unpacker_peek_next_object_type(msgpack_unpacker_t* uk)
695
+ {
696
+ int b = get_head_byte(uk);
697
+ if(b < 0) {
698
+ return b;
699
+ }
700
+
701
+ SWITCH_RANGE_BEGIN(b)
702
+ SWITCH_RANGE(b, 0x00, 0x7f) // Positive Fixnum
703
+ return TYPE_INTEGER;
704
+
705
+ SWITCH_RANGE(b, 0xe0, 0xff) // Negative Fixnum
706
+ return TYPE_INTEGER;
707
+
708
+ SWITCH_RANGE(b, 0xa0, 0xbf) // FixRaw
709
+ return TYPE_RAW;
710
+
711
+ SWITCH_RANGE(b, 0x90, 0x9f) // FixArray
712
+ return TYPE_ARRAY;
713
+
714
+ SWITCH_RANGE(b, 0x80, 0x8f) // FixMap
715
+ return TYPE_MAP;
716
+
717
+ SWITCH_RANGE(b, 0xc0, 0xdf) // Variable
718
+ switch(b) {
719
+ case 0xc0: // nil
720
+ return TYPE_NIL;
721
+
722
+ case 0xc2: // false
723
+ case 0xc3: // true
724
+ return TYPE_BOOLEAN;
725
+
726
+ case 0xca: // float
727
+ case 0xcb: // double
728
+ return TYPE_FLOAT;
729
+
730
+ case 0xcc: // unsigned int 8
731
+ case 0xcd: // unsigned int 16
732
+ case 0xce: // unsigned int 32
733
+ case 0xcf: // unsigned int 64
734
+ return TYPE_INTEGER;
735
+
736
+ case 0xd0: // signed int 8
737
+ case 0xd1: // signed int 16
738
+ case 0xd2: // signed int 32
739
+ case 0xd3: // signed int 64
740
+ return TYPE_INTEGER;
741
+
742
+ case 0xd9: // raw 8 / str 8
743
+ case 0xda: // raw 16 / str 16
744
+ case 0xdb: // raw 32 / str 32
745
+ return TYPE_RAW;
746
+
747
+ case 0xc4: // bin 8
748
+ case 0xc5: // bin 16
749
+ case 0xc6: // bin 32
750
+ return TYPE_RAW;
751
+
752
+ case 0xdc: // array 16
753
+ case 0xdd: // array 32
754
+ return TYPE_ARRAY;
755
+
756
+ case 0xde: // map 16
757
+ case 0xdf: // map 32
758
+ return TYPE_MAP;
759
+
760
+ default:
761
+ return PRIMITIVE_INVALID_BYTE;
762
+ }
763
+
764
+ SWITCH_RANGE_DEFAULT
765
+ return PRIMITIVE_INVALID_BYTE;
766
+
767
+ SWITCH_RANGE_END
768
+ }
769
+
770
+ int msgpack_unpacker_skip_nil(msgpack_unpacker_t* uk)
771
+ {
772
+ int b = get_head_byte(uk);
773
+ if(b < 0) {
774
+ return b;
775
+ }
776
+ if(b == 0xc0) {
777
+ return 1;
778
+ }
779
+ return 0;
780
+ }
781
+