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.
- checksums.yaml +7 -0
- data/.gitignore +22 -0
- data/.travis.yml +5 -0
- data/ChangeLog +87 -0
- data/README.rdoc +180 -0
- data/Rakefile +94 -0
- data/cbor.gemspec +26 -0
- data/doclib/cbor.rb +80 -0
- data/doclib/cbor/buffer.rb +193 -0
- data/doclib/cbor/core_ext.rb +133 -0
- data/doclib/cbor/error.rb +14 -0
- data/doclib/cbor/packer.rb +133 -0
- data/doclib/cbor/simple.rb +15 -0
- data/doclib/cbor/tagged.rb +16 -0
- data/doclib/cbor/unpacker.rb +138 -0
- data/ext/cbor/buffer.c +693 -0
- data/ext/cbor/buffer.h +469 -0
- data/ext/cbor/buffer_class.c +516 -0
- data/ext/cbor/buffer_class.h +41 -0
- data/ext/cbor/cbor.h +69 -0
- data/ext/cbor/compat.h +136 -0
- data/ext/cbor/core_ext.c +181 -0
- data/ext/cbor/core_ext.h +35 -0
- data/ext/cbor/extconf.rb +25 -0
- data/ext/cbor/packer.c +169 -0
- data/ext/cbor/packer.h +337 -0
- data/ext/cbor/packer_class.c +304 -0
- data/ext/cbor/packer_class.h +39 -0
- data/ext/cbor/rbinit.c +51 -0
- data/ext/cbor/renamer.h +56 -0
- data/ext/cbor/rmem.c +103 -0
- data/ext/cbor/rmem.h +118 -0
- data/ext/cbor/sysdep.h +135 -0
- data/ext/cbor/sysdep_endian.h +59 -0
- data/ext/cbor/sysdep_types.h +55 -0
- data/ext/cbor/unpacker.c +735 -0
- data/ext/cbor/unpacker.h +133 -0
- data/ext/cbor/unpacker_class.c +417 -0
- data/ext/cbor/unpacker_class.h +39 -0
- data/lib/cbor.rb +9 -0
- data/lib/cbor/version.rb +3 -0
- data/spec/buffer_io_spec.rb +260 -0
- data/spec/buffer_spec.rb +576 -0
- data/spec/cases.cbor +0 -0
- data/spec/cases.cbor_stream +0 -0
- data/spec/cases.json +1 -0
- data/spec/cases.msg +0 -0
- data/spec/cases_compact.msg +0 -0
- data/spec/cases_spec.rb +39 -0
- data/spec/format_spec.rb +445 -0
- data/spec/packer_spec.rb +127 -0
- data/spec/random_compat.rb +24 -0
- data/spec/spec_helper.rb +45 -0
- data/spec/unpacker_spec.rb +238 -0
- metadata +196 -0
data/ext/cbor/unpacker.c
ADDED
@@ -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
|
+
|