File Coverage

cbor_free_decode.c
Criterion Covered Total %
statement 403 431 93.5
branch 175 200 87.5
condition n/a
subroutine n/a
pod n/a
total 578 631 91.6


line stmt bran cond sub pod time code
1             #include "easyxs/init.h"
2              
3             #include "cbor_free_common.h"
4             #include "cbor_free_decode.h"
5              
6             #include
7             #include
8              
9             // For ntohs and ntohl
10             #include
11              
12             #define _IS_INCOMPLETE(decstate, len) \
13             ((len + decstate->curbyte) > decstate->end)
14              
15             #define _SET_INCOMPLETE(decstate, len) \
16             decstate->incomplete_by = (len + decstate->curbyte) - decstate->end;
17              
18             #define _RETURN_IF_INCOMPLETE( decstate, len, toreturn ) \
19             if (_IS_INCOMPLETE(decstate, len)) { \
20             _SET_INCOMPLETE(decstate, len); \
21             return toreturn; \
22             }
23              
24             #define _RETURN_IF_SET_INCOMPLETE(decstate, toreturn) \
25             if (decstate->incomplete_by) return toreturn;
26              
27             #define SHOULD_VALIDATE_UTF8(decstate, major_type) \
28             major_type == CBOR_TYPE_UTF8 \
29             || decstate->string_decode_mode == CBF_STRING_DECODE_ALWAYS
30              
31             //----------------------------------------------------------------------
32              
33             // Basically ntohll(), but it accepts a pointer.
34 19           static inline UV _buffer_u64_to_uv( unsigned char *buffer ) {
35 19           UV num = 0;
36              
37             #if IS_64_BIT
38 19           num |= *(buffer++);
39 19           num <<= 8;
40              
41 19           num |= *(buffer++);
42 19           num <<= 8;
43              
44 19           num |= *(buffer++);
45 19           num <<= 8;
46              
47 19           num |= *(buffer++);
48 19           num <<= 8;
49             #else
50             buffer += 4;
51             #endif
52              
53 19           num |= *(buffer++);
54 19           num <<= 8;
55              
56 19           num |= *(buffer++);
57 19           num <<= 8;
58              
59 19           num |= *(buffer++);
60 19           num <<= 8;
61              
62 19           num |= *(buffer++);
63              
64 19           return num;
65             }
66              
67             const char *MAJOR_TYPE_DESCRIPTION[] = {
68             "unsigned integer",
69             "negative integer",
70             "byte string",
71             "text string",
72             "array",
73             "map",
74             "tag",
75             "miscellaneous",
76             };
77              
78             //----------------------------------------------------------------------
79             // Croakers
80              
81             static const char* UV_TO_STR_TMPL = (sizeof(UV) == 8 ? "%llu" : "%lu");
82             static const char* IV_TO_STR_TMPL = (sizeof(UV) == 8 ? "%lld" : "%ld");
83              
84 23           UV _uv_to_str(UV num, char *numstr, const char strlen) {
85 23 50         return my_snprintf( numstr, strlen, UV_TO_STR_TMPL, num );
    50          
86             }
87              
88 2           UV _iv_to_str(IV num, char *numstr, const char strlen) {
89 2 50         return my_snprintf( numstr, strlen, IV_TO_STR_TMPL, num );
    50          
90             }
91              
92 206           void _free_decode_state_if_not_persistent( pTHX_ decode_ctx* decstate ) {
93 206 100         if (!(decstate->flags & CBF_FLAG_PERSIST_STATE)) {
94 195           free_decode_state(aTHX_ decstate);
95             }
96 206           }
97              
98 146           static inline void _croak_incomplete( pTHX_ decode_ctx* decstate ) {
99              
100 292           SV* args[2] = {
101 146           newSVpvs("Incomplete"),
102 146           newSVuv(decstate->incomplete_by),
103             };
104              
105 146           _free_decode_state_if_not_persistent(aTHX_ decstate);
106              
107 146           cbf_die_with_arguments( aTHX_ 2, args );
108 0           }
109              
110 49           static inline void _croak_invalid_control( pTHX_ decode_ctx* decstate ) {
111 49           const uint8_t ord = (uint8_t) *(decstate->curbyte);
112 49           UV offset = decstate->curbyte - decstate->start;
113              
114 49           _free_decode_state_if_not_persistent(aTHX_ decstate);
115              
116 147           SV* args[3] = {
117 49           newSVpvs("InvalidControl"),
118 49           newSVuv(ord),
119 49           newSVuv(offset),
120             };
121              
122 49           cbf_die_with_arguments( aTHX_ 3, args );
123              
124             assert(0);
125 0           }
126              
127 2           void _croak_invalid_utf8( pTHX_ decode_ctx* decstate, char *string, STRLEN len ) {
128 2           _free_decode_state_if_not_persistent(aTHX_ decstate);
129              
130 4           SV* args[2] = {
131 2           newSVpvs("InvalidUTF8"),
132 2           newSVpvn(string, len),
133             };
134              
135 2           cbf_die_with_arguments( aTHX_ 2, args );
136              
137             assert(0);
138 0           }
139              
140 8           void _croak_invalid_map_key( pTHX_ decode_ctx* decstate ) {
141 8           const uint8_t byte = decstate->curbyte[0];
142 8           UV offset = decstate->curbyte - decstate->start;
143              
144 8           _free_decode_state_if_not_persistent(aTHX_ decstate);
145              
146             char bytebuf[5];
147              
148             char *bytestr;
149              
150 8           switch (byte) {
151             case CBOR_FALSE:
152 2           bytestr = "false";
153 2           break;
154             case CBOR_TRUE:
155 1           bytestr = "true";
156 1           break;
157             case CBOR_NULL:
158 1           bytestr = "null";
159 1           break;
160             case CBOR_UNDEFINED:
161 1           bytestr = "undefined";
162 1           break;
163             case CBOR_HALF_FLOAT:
164 0           bytestr = "half-float";
165             case CBOR_FLOAT:
166 0           bytestr = "float";
167             case CBOR_DOUBLE:
168 1           bytestr = "double float";
169 1           break;
170             default:
171 2           switch ((byte & 0xe0) >> 5) {
172             case CBOR_TYPE_ARRAY:
173 1           bytestr = "array";
174 1           break;
175             case CBOR_TYPE_MAP:
176 1           bytestr = "map";
177 1           break;
178             default:
179 0 0         my_snprintf( bytebuf, 5, "0x%02x", byte );
180 0           bytestr = bytebuf;
181             }
182             }
183              
184 24           SV* args[3] = {
185 8           newSVpvs("InvalidMapKey"),
186 8           newSVpv(bytestr, 0),
187 8           newSVuv(offset),
188             };
189              
190 8           cbf_die_with_arguments( aTHX_ 3, args );
191              
192             assert(0);
193 0           }
194              
195 0           void _croak_cannot_decode_64bit( pTHX_ decode_ctx* decstate ) {
196 0           UV offset = decstate->curbyte - decstate->start;
197              
198 0           _free_decode_state_if_not_persistent(aTHX_ decstate);
199              
200 0           SV* args[3] = {
201 0           newSVpvs("CannotDecode64Bit"),
202 0           newSVpvn( decstate->curbyte, 8),
203 0           newSVuv(offset),
204             };
205              
206 0           cbf_die_with_arguments( aTHX_ 3, args );
207              
208             assert(0);
209 0           }
210              
211 1           void _croak_cannot_decode_negative( pTHX_ decode_ctx* decstate, UV abs, STRLEN offset ) {
212 1           _free_decode_state_if_not_persistent(aTHX_ decstate);
213              
214 3           SV* args[3] = {
215 1           newSVpvs("NegativeIntTooLow"),
216 1           newSVuv(abs),
217 1           newSVuv(offset),
218             };
219              
220 1           cbf_die_with_arguments( aTHX_ 3, args );
221              
222             assert(0);
223 0           }
224              
225 33           void _warn_unhandled_tag( pTHX_ UV tagnum, U8 value_major_type ) {
226             char tmpl[255];
227 33 50         my_snprintf( tmpl, sizeof(tmpl), "Ignoring unrecognized CBOR tag #%s (major type %%u, %%s)!", UV_TO_STR_TMPL );
228              
229 33           warn(tmpl, tagnum, value_major_type, MAJOR_TYPE_DESCRIPTION[value_major_type]);
230 33           }
231              
232             //----------------------------------------------------------------------
233              
234 96           static inline void _validate_utf8_string_if_needed( pTHX_ decode_ctx* decstate, char *buffer, STRLEN len ) {
235              
236 96 100         if (!(decstate->flags & CBF_FLAG_NAIVE_UTF8) && !is_utf8_string( (U8 *)buffer, len)) {
    100          
237 2           _croak_invalid_utf8( aTHX_ decstate, buffer, len );
238             }
239 94           }
240              
241             //----------------------------------------------------------------------
242             // DECODER:
243             //----------------------------------------------------------------------
244              
245             // Sets incomplete_by.
246 6068           static inline UV _parse_for_uint_len2( pTHX_ decode_ctx* decstate ) {
247             UV ret;
248              
249 6068           switch (CONTROL_BYTE_LENGTH_TYPE(*decstate->curbyte)) {
250             case CBOR_LENGTH_SMALL:
251              
252 264 100         _RETURN_IF_INCOMPLETE( decstate, 2, 0 );
253              
254 258           ++decstate->curbyte;
255              
256 258           ret = (uint8_t) decstate->curbyte[0];
257              
258 258           ++decstate->curbyte;
259              
260 258           break;
261              
262             case CBOR_LENGTH_MEDIUM:
263 56 100         _RETURN_IF_INCOMPLETE( decstate, 3, 0);
264              
265 46           ++decstate->curbyte;
266              
267 46           ret = ntohs( *((uint16_t *) decstate->curbyte) );
268              
269 46           decstate->curbyte += 2;
270              
271 46           break;
272              
273             case CBOR_LENGTH_LARGE:
274 162 100         _RETURN_IF_INCOMPLETE( decstate, 5, 0);
275              
276 128           ++decstate->curbyte;
277              
278 128           ret = ntohl( *((uint32_t *) decstate->curbyte) );
279              
280 128           decstate->curbyte += 4;
281              
282 128           break;
283              
284             case CBOR_LENGTH_HUGE:
285 59 100         _RETURN_IF_INCOMPLETE( decstate, 9, 0);
286              
287 19           ++decstate->curbyte;
288              
289             #if !IS_64_BIT
290              
291             if (decstate->curbyte[0] || decstate->curbyte[1] || decstate->curbyte[2] || decstate->curbyte[3]) {
292             _croak_cannot_decode_64bit( aTHX_ decstate );
293             }
294             #endif
295 19           ret = _buffer_u64_to_uv( (uint8_t *) decstate->curbyte );
296              
297 19           decstate->curbyte += 8;
298              
299 19           break;
300              
301             case 0x1c:
302             case 0x1d:
303             case 0x1e:
304             case 0x1f: // indefinite must be handled outside this function.
305 21           _croak_invalid_control( aTHX_ decstate );
306 0           return 0; // Silence compiler warning.
307              
308             default:
309 5506           ret = CONTROL_BYTE_LENGTH_TYPE(*decstate->curbyte);
310              
311 5506           decstate->curbyte++;
312             }
313              
314 5957           return ret;
315             }
316              
317             //----------------------------------------------------------------------
318              
319             // Sets incomplete_by.
320 171           SV *_decode_array( pTHX_ decode_ctx* decstate ) {
321 171           AV *array = newAV();
322 171           sv_2mortal( (SV *) array );
323              
324 171           SV *cur = NULL;
325              
326 171 100         if (CONTROL_BYTE_LENGTH_TYPE(*decstate->curbyte) == CBOR_LENGTH_INDEFINITE) {
327 39           ++decstate->curbyte;
328              
329             while (1) {
330 83 100         _RETURN_IF_INCOMPLETE( decstate, 1, NULL );
331              
332 79 100         if ( decstate->curbyte[0] == '\xff') {
333 12           ++decstate->curbyte;
334 12           break;
335             }
336              
337 67           cur = cbf_decode_one( aTHX_ decstate );
338              
339 67 100         _RETURN_IF_SET_INCOMPLETE(decstate, NULL);
340              
341 44           av_push(array, cur);
342 56           }
343             }
344             else {
345 132           SSize_t array_length = _parse_for_uint_len2( aTHX_ decstate );
346 129 100         _RETURN_IF_SET_INCOMPLETE(decstate, NULL);
347              
348 127 100         if (array_length) {
349 108           av_fill(array, array_length - 1);
350              
351             SSize_t i;
352 587 100         for (i=0; i
353 533           cur = cbf_decode_one( aTHX_ decstate );
354 484 100         _RETURN_IF_SET_INCOMPLETE(decstate, NULL);
355              
356 479 50         if (!av_store(array, i, cur)) {
357 0           _croak("Failed to store item in array!");
358             }
359             }
360             }
361             }
362              
363 85           return newRV_inc( (SV *) array );
364             }
365              
366             // Sets incomplete_by.
367 1909           UV _decode_uint( pTHX_ decode_ctx* decstate ) {
368              
369 1909 100         if (CONTROL_BYTE_LENGTH_TYPE(*decstate->curbyte) == CBOR_LENGTH_INDEFINITE) {
370 1           _croak_invalid_control( aTHX_ decstate );
371             }
372              
373 1908           return _parse_for_uint_len2( aTHX_ decstate );
374             }
375              
376             // Sets incomplete_by.
377 46           IV _decode_negint( pTHX_ decode_ctx* decstate ) {
378              
379 46 100         if (CONTROL_BYTE_LENGTH_TYPE(*decstate->curbyte) == CBOR_LENGTH_INDEFINITE) {
380 1           _croak_invalid_control( aTHX_ decstate );
381             }
382              
383 45           UV positive = _parse_for_uint_len2( aTHX_ decstate );
384 42 100         _RETURN_IF_SET_INCOMPLETE(decstate, 0);
385              
386             #if IS_64_BIT
387 26 100         if (positive >= 0x8000000000000000U) {
388 1           _croak_cannot_decode_negative( aTHX_ decstate, positive, decstate->curbyte - decstate->start - 8 );
389             }
390             #else
391             if (positive >= 0x80000000U) {
392             STRLEN offset = decstate->curbyte - decstate->start;
393              
394             if (CONTROL_BYTE_LENGTH_TYPE(*decstate->curbyte) == CBOR_LENGTH_LARGE) {
395             offset -= 4;
396             }
397             else {
398             offset -= 8;
399             }
400              
401             _croak_cannot_decode_negative( aTHX_ decstate, positive, offset );
402             }
403             #endif
404              
405 25           return( -1 - (int64_t) positive );
406             }
407              
408             // Sets incomplete_by.
409             // Return indicates whether string_h has SV.
410 3726           bool _decode_str( pTHX_ decode_ctx* decstate, union numbuf_or_sv* string_u ) {
411              
412 3726 100         if (CONTROL_BYTE_LENGTH_TYPE(*decstate->curbyte) == CBOR_LENGTH_INDEFINITE) {
413 11           ++decstate->curbyte;
414              
415 11           SV *string = newSVpvs(""); /* 5.10.0 lacks newSVpvs_flags() */
416 11           sv_2mortal(string);
417 11           string_u->sv = string;
418              
419             while (1) {
420 23 100         _RETURN_IF_INCOMPLETE( decstate, 1, false );
421              
422 21 100         if (decstate->curbyte[0] == '\xff') {
423 7           ++decstate->curbyte;
424 7           break;
425             }
426              
427             //TODO: Require the same major type.
428              
429 14           SV *cur = cbf_decode_one( aTHX_ decstate );
430              
431 14 100         _RETURN_IF_SET_INCOMPLETE( decstate, false );
432              
433 12           sv_2mortal(cur);
434              
435 12           sv_catsv(string, cur);
436 12           }
437              
438 7           SvREFCNT_inc(string);
439              
440 7           return true;
441             }
442              
443 3715           string_u->numbuf.num.uv = _parse_for_uint_len2( aTHX_ decstate );
444 3709 100         _RETURN_IF_SET_INCOMPLETE(decstate, false);
445              
446 3668 100         _RETURN_IF_INCOMPLETE( decstate, string_u->numbuf.num.uv, false );
447              
448 3637           string_u->numbuf.buffer = decstate->curbyte;
449              
450 3637           decstate->curbyte += string_u->numbuf.num.uv;
451              
452 3637           return false;
453             }
454              
455             // Sets incomplete_by.
456 2561           void _decode_hash_entry( pTHX_ decode_ctx* decstate, HV *hash ) {
457 2566 100         _RETURN_IF_INCOMPLETE( decstate, 1, );
458              
459             union numbuf_or_sv my_key;
460 2559           my_key.numbuf.buffer = NULL;
461              
462             // This is going to be a hash key, so it can’t usefully be
463             // anything but a string/PV.
464             I32 keylen;
465             char *keystr;
466              
467 2559           bool my_key_has_sv = false;
468              
469 2559           uint8_t major_type = CONTROL_BYTE_MAJOR_TYPE(*decstate->curbyte);
470              
471 2559           switch (major_type) {
472             case CBOR_TYPE_UINT:
473 23           my_key.numbuf.num.uv = _decode_uint( aTHX_ decstate );
474 23 100         _RETURN_IF_SET_INCOMPLETE(decstate, );
475              
476 22           keystr = (char *) decstate->scratch.bytes;
477 22           keylen = _uv_to_str( my_key.numbuf.num.uv, keystr, sizeof(decstate->scratch.bytes));
478             // fprintf(stderr, "key (%p) is uint: %.*s\n", keystr, keylen, keystr);
479              
480 22           break;
481              
482             case CBOR_TYPE_NEGINT:
483 3           my_key.numbuf.num.iv = _decode_negint( aTHX_ decstate );
484 3 100         _RETURN_IF_SET_INCOMPLETE(decstate, );
485              
486 2           keystr = (char *) decstate->scratch.bytes;
487 2           keylen = _iv_to_str( my_key.numbuf.num.iv, keystr, sizeof(decstate->scratch.bytes));
488              
489 2           break;
490              
491             case CBOR_TYPE_BINARY:
492             case CBOR_TYPE_UTF8:
493 2525           my_key_has_sv = _decode_str( aTHX_ decstate, &my_key );
494 2525 100         _RETURN_IF_SET_INCOMPLETE(decstate, );
495              
496 2522 100         if (!my_key_has_sv) {
497 2519 50         if (my_key.numbuf.num.uv > 0x7fffffffU) {
498 0           _croak("key too long!");
499             }
500              
501 2519           keystr = my_key.numbuf.buffer;
502              
503 2519 100         if (SHOULD_VALIDATE_UTF8(decstate, major_type)) {
    50          
504 30           _validate_utf8_string_if_needed( aTHX_ decstate, keystr, my_key.numbuf.num.uv );
505              
506 29 50         keylen = decstate->string_decode_mode == CBF_STRING_DECODE_NEVER ? my_key.numbuf.num.uv : -my_key.numbuf.num.uv;
507             }
508             else {
509 2489           keylen = my_key.numbuf.num.uv;
510             }
511             }
512              
513 2521           break;
514              
515             default:
516 8           _croak_invalid_map_key( aTHX_ decstate);
517 0           return; // Silence compiler warning.
518             }
519              
520 2545           SV *curval = cbf_decode_one( aTHX_ decstate );
521              
522 2545 100         if (decstate->incomplete_by) {
523 3 100         if (my_key_has_sv) {
524 3           SvREFCNT_dec( my_key.sv );
525             }
526             }
527 2542 100         else if (my_key_has_sv) {
528 2           hv_store_ent(hash, my_key.sv, curval, 0);
529             }
530             else {
531 2545           hv_store(hash, keystr, keylen, curval, 0);
532             }
533             }
534              
535             // Sets incomplete_by.
536 67           SV *_decode_map( pTHX_ decode_ctx* decstate ) {
537              
538 67           HV *hash = newHV();
539 67           sv_2mortal( (SV *) hash );
540              
541 67 100         if (CONTROL_BYTE_LENGTH_TYPE(*decstate->curbyte) == CBOR_LENGTH_INDEFINITE) {
542 8           ++decstate->curbyte;
543              
544             while (1) {
545 13 100         _RETURN_IF_INCOMPLETE( decstate, 1, NULL );
546              
547 11 100         if (decstate->curbyte[0] == '\xff') {
548 4           ++decstate->curbyte;
549 4           break;
550             }
551              
552 7           _decode_hash_entry( aTHX_ decstate, hash );
553              
554             // TODO: Recursively decref all hash members.
555 7 100         if ( decstate->incomplete_by ) {
556 2           return NULL;
557             }
558 9           }
559             }
560             else {
561 59           SSize_t keycount = _parse_for_uint_len2( aTHX_ decstate );
562 56 100         if ( decstate->incomplete_by ) {
563 5           return NULL;
564             }
565              
566 51 100         if (keycount) {
567 2576 100         while (keycount > 0) {
568 2554           _decode_hash_entry( aTHX_ decstate, hash );
569              
570             // TODO: Recursively decref all hash members.
571 2545 100         if ( decstate->incomplete_by ) {
572 8           return NULL;
573             }
574              
575 2537           --keycount;
576             }
577             }
578             }
579              
580 38           return newRV_inc( (SV *) hash);
581             }
582              
583             //----------------------------------------------------------------------
584              
585             // Taken from RFC 7049:
586 7           double decode_half_float(uint8_t *halfp) {
587 7           int half = (halfp[0] << 8) + halfp[1];
588 7           int exp = (half >> 10) & 0x1f;
589 7           int mant = half & 0x3ff;
590             double val;
591 7 50         if (exp == 0) val = ldexp(mant, -24);
592 7 100         else if (exp != 31) val = ldexp(mant + 1024, exp - 25);
593 6 100         else val = mant == 0 ? INFINITY : NAN;
594 7 100         return half & 0x8000 ? -val : val;
595             }
596              
597 24           static inline float _decode_float_to_host( pTHX_ decode_ctx* decstate, uint8_t *ptr ) {
598 24           *((uint32_t *) decstate->scratch.bytes) = ntohl( *((uint32_t *) ptr) );
599              
600 24           return decstate->scratch.as_float;
601             }
602              
603 63           static inline double _decode_double_to_le( decode_ctx* decstate, uint8_t *ptr ) {
604 63           decstate->scratch.bytes[0] = ptr[7];
605 63           decstate->scratch.bytes[1] = ptr[6];
606 63           decstate->scratch.bytes[2] = ptr[5];
607 63           decstate->scratch.bytes[3] = ptr[4];
608 63           decstate->scratch.bytes[4] = ptr[3];
609 63           decstate->scratch.bytes[5] = ptr[2];
610 63           decstate->scratch.bytes[6] = ptr[1];
611 63           decstate->scratch.bytes[7] = ptr[0];
612              
613 63           return decstate->scratch.as_double;
614             }
615              
616             //----------------------------------------------------------------------
617              
618             // Sets incomplete_by.
619 1201           static inline SV *_decode_str_to_sv( pTHX_ decode_ctx* decstate ) {
620             union numbuf_or_sv string;
621              
622 1201 100         if (_decode_str( aTHX_ decstate, &string )) {
623 4           return string.sv;
624             }
625              
626 1191 100         _RETURN_IF_SET_INCOMPLETE(decstate, NULL);
627              
628 1195           return newSVpvn( string.numbuf.buffer, string.numbuf.num.uv );
629             }
630              
631             // Sets incomplete_by.
632 3949           SV *cbf_decode_one( pTHX_ decode_ctx* decstate ) {
633 3949           SV *ret = NULL;
634              
635 3949 100         _RETURN_IF_INCOMPLETE( decstate, 1, NULL );
636              
637 3938           uint8_t control_byte = *decstate->curbyte;
638              
639             // fprintf(stderr, "major type: %d\n", control->pieces.major_type);
640              
641 3938           switch (CONTROL_BYTE_MAJOR_TYPE(control_byte)) {
642             case CBOR_TYPE_UINT:
643 1886           ret = newSVuv( _decode_uint( aTHX_ decstate ) );
644 1882 100         if ( decstate->incomplete_by ) {
645 15           SvREFCNT_dec(ret);
646 188           return NULL;
647             }
648              
649 1867           break;
650             case CBOR_TYPE_NEGINT:
651 43           ret = newSViv( _decode_negint( aTHX_ decstate ) );
652 38 100         if ( decstate->incomplete_by ) {
653 15           SvREFCNT_dec(ret);
654 15           return NULL;
655             }
656              
657 23           break;
658             case CBOR_TYPE_BINARY:
659             case CBOR_TYPE_UTF8:
660 1201           ret = _decode_str_to_sv( aTHX_ decstate );
661 1195 100         _RETURN_IF_SET_INCOMPLETE(decstate, NULL);
662              
663 1122 100         if (SHOULD_VALIDATE_UTF8(decstate, CONTROL_BYTE_MAJOR_TYPE(control_byte))) {
    100          
664 66 50         _validate_utf8_string_if_needed( aTHX_ decstate, SvPV_nolen(ret), SvCUR(ret));
665              
666             // Always set the UTF8 flag, even if it’s not needed.
667             // This helps ensure that text strings will round-trip
668             // through Perl.
669 65 100         if (decstate->string_decode_mode != CBF_STRING_DECODE_NEVER) SvUTF8_on(ret);
670             }
671              
672 1121           break;
673             case CBOR_TYPE_ARRAY:
674 171           ret = _decode_array( aTHX_ decstate );
675 119 100         _RETURN_IF_SET_INCOMPLETE(decstate, NULL);
676              
677 85           break;
678             case CBOR_TYPE_MAP:
679 67           ret = _decode_map( aTHX_ decstate );
680 55 100         _RETURN_IF_SET_INCOMPLETE(decstate, NULL);
681              
682 38           break;
683             case CBOR_TYPE_TAG:
684              
685 198 100         if (CONTROL_BYTE_LENGTH_TYPE(control_byte) == CBOR_LENGTH_INDEFINITE) {
686 1           _croak_invalid_control( aTHX_ decstate );
687             }
688              
689 197           UV tagnum = _parse_for_uint_len2( aTHX_ decstate );
690 194 100         _RETURN_IF_SET_INCOMPLETE(decstate, NULL);
691              
692 179           uint8_t value_major_type = CONTROL_BYTE_MAJOR_TYPE(*decstate->curbyte);
693              
694 191 100         if (tagnum == CBOR_TAG_SHAREDREF && decstate->reflist) {
    100          
695 12 50         if (value_major_type != CBOR_TYPE_UINT) {
696             char tmpl[255];
697 0 0         my_snprintf( tmpl, sizeof(tmpl), "Shared ref type must be uint, not %%u (%%s)!" );
698 0           croak(tmpl, value_major_type, MAJOR_TYPE_DESCRIPTION[value_major_type]);
699             }
700              
701 12           UV refnum = _parse_for_uint_len2( aTHX_ decstate );
702 12 50         _RETURN_IF_SET_INCOMPLETE(decstate, NULL);
703              
704 12 50         if (refnum >= decstate->reflistlen) {
705 0           _croak("Missing shareable!");
706             }
707              
708 12           ret = decstate->reflist[refnum];
709 12           SvREFCNT_inc(ret);
710             }
711             else {
712 167           ret = cbf_decode_one( aTHX_ decstate );
713 167 100         _RETURN_IF_SET_INCOMPLETE(decstate, NULL);
714              
715 162 100         if (tagnum == CBOR_TAG_INDIRECTION) {
716 17           ret = newRV_noinc(ret);
717             }
718 145 100         else if (tagnum == CBOR_TAG_SHAREABLE && decstate->reflist) {
    100          
719 12           ++decstate->reflistlen;
720 12 50         Renew( decstate->reflist, decstate->reflistlen, void * );
721              
722 12           decstate->reflist[ decstate->reflistlen - 1 ] = (SV *) ret;
723             }
724              
725 133 100         else if (decstate->tag_handler) {
726 102           HV *my_tag_handler = decstate->tag_handler;
727              
728 102           SV **handler_cr = hv_fetch( my_tag_handler, (char *) &tagnum, sizeof(UV), 0 );
729              
730 102 100         if (handler_cr && *handler_cr && SvOK(*handler_cr)) {
    50          
    100          
    50          
    50          
731 100           ret = cbf_call_scalar_with_arguments( aTHX_ *handler_cr, 1, &ret );
732             }
733             else {
734 102           _warn_unhandled_tag( aTHX_ tagnum, value_major_type );
735             }
736             }
737             else {
738 31           _warn_unhandled_tag( aTHX_ tagnum, value_major_type );
739             }
740             }
741              
742 174           break;
743             case CBOR_TYPE_OTHER:
744 372           switch (control_byte) {
745             case CBOR_FALSE:
746 3           ret = newSVsv( cbf_get_false() );
747 3           ++decstate->curbyte;
748 3           break;
749              
750             case CBOR_TRUE:
751 6           ret = newSVsv( cbf_get_true() );
752 6           ++decstate->curbyte;
753 6           break;
754              
755             case CBOR_NULL:
756             case CBOR_UNDEFINED:
757 230           ret = &PL_sv_undef;
758 230           ++decstate->curbyte;
759 230           break;
760              
761             case CBOR_HALF_FLOAT:
762 9 100         _RETURN_IF_INCOMPLETE( decstate, 3, NULL );
763              
764 7           ret = newSVnv( decode_half_float( (uint8_t *) (1 + decstate->curbyte) ) );
765              
766 7           decstate->curbyte += 3;
767 7           break;
768              
769             case CBOR_FLOAT:
770 28 100         _RETURN_IF_INCOMPLETE( decstate, 5, NULL );
771              
772             float decoded_flt;
773              
774             #if IS_LITTLE_ENDIAN
775 24           decoded_flt = _decode_float_to_host( aTHX_ decstate, (uint8_t *) (1 + decstate->curbyte ) );
776             #else
777             decoded_flt = *( (float *) (1 + decstate->curbyte) );
778             #endif
779              
780 24           ret = newSVnv( (NV) decoded_flt );
781              
782 24           decstate->curbyte += 5;
783 24           break;
784              
785             case CBOR_DOUBLE:
786 71 100         _RETURN_IF_INCOMPLETE( decstate, 9, NULL );
787              
788             double decoded_dbl;
789              
790             #if IS_LITTLE_ENDIAN
791 63           decoded_dbl = _decode_double_to_le( decstate, (uint8_t *) (1 + decstate->curbyte ) );
792             #else
793             decoded_dbl = *( (double *) (1 + decstate->curbyte) );
794             #endif
795              
796 63           ret = newSVnv( (NV) decoded_dbl );
797              
798 63           decstate->curbyte += 9;
799 63           break;
800              
801             default:
802 25           _croak_invalid_control( aTHX_ decstate );
803             }
804              
805 333           break;
806              
807             default:
808 0           _croak("Unknown type!");
809             }
810              
811 3840           return ret;
812             }
813              
814             /*
815             * Possible states:
816             *
817             * 1) We’re initializing.
818             * 2) We just concat’ed two SVPVs (same as initializing).
819             * 3) We just shortened from the beginning.
820             */
821              
822 629           void renew_decode_state_buffer( pTHX_ decode_ctx *decode_state, SV *cbor ) {
823 629           STRLEN cborlen = SvCUR(cbor);
824              
825 629           char *cborstr = SvPVX(cbor);
826              
827             STRLEN offset;
828 629 100         if (decode_state->curbyte == NULL) {
829 599           offset = 0;
830             }
831             else {
832 30           offset = decode_state->curbyte - decode_state->start;
833             }
834              
835 629           decode_state->start = cborstr;
836 629           decode_state->size = cborlen;
837 629           decode_state->curbyte = cborstr + offset;
838 629           decode_state->end = cborstr + cborlen;
839 629           }
840              
841 18           void advance_decode_state_buffer( pTHX_ decode_ctx *decode_state ) {
842 18           STRLEN diff = decode_state->curbyte - decode_state->start;
843              
844 18           decode_state->start = decode_state->curbyte;
845 18           decode_state->size -= diff;
846 18           }
847              
848 579           decode_ctx* create_decode_state( pTHX_ SV *cbor, HV *tag_handler, UV flags ) {
849             decode_ctx *decode_state;
850 579           Newx( decode_state, 1, decode_ctx );
851              
852 579           decode_state->curbyte = NULL;
853              
854 579 100         if (cbor) {
855 472           renew_decode_state_buffer( aTHX_ decode_state, cbor );
856             }
857              
858 579           decode_state->tag_handler = tag_handler;
859 579 50         if (NULL != tag_handler) {
860 0           SvREFCNT_inc((SV *) tag_handler);
861             }
862              
863 579           decode_state->reflist = NULL;
864 579           decode_state->reflistlen = 0;
865 579           decode_state->flags = flags;
866 579           decode_state->incomplete_by = 0;
867              
868 579           decode_state->string_decode_mode = CBF_STRING_DECODE_CBOR;
869              
870 579 50         if (flags & CBF_FLAG_PRESERVE_REFERENCES) {
871 0           ensure_reflist_exists( aTHX_ decode_state );
872             }
873              
874 579           return decode_state;
875             }
876              
877 4           void ensure_reflist_exists( pTHX_ decode_ctx* decode_state) {
878 4 50         if (NULL == decode_state->reflist) {
879 4           Newx( decode_state->reflist, 0, void * );
880             }
881 4           }
882              
883 583           void delete_reflist( pTHX_ decode_ctx* decode_state) {
884 583 100         if (NULL != decode_state->reflist) {
885 4           Safefree(decode_state->reflist);
886 4           decode_state->reflist = NULL;
887 4           decode_state->reflistlen = 0;
888             }
889 583           }
890              
891 4           void reset_reflist_if_needed( pTHX_ decode_ctx* decode_state) {
892 4 100         if (decode_state->reflistlen) {
893 2           delete_reflist( aTHX_ decode_state );
894 2           ensure_reflist_exists( aTHX_ decode_state );
895             }
896 4           }
897              
898 579           void free_decode_state( pTHX_ decode_ctx* decode_state) {
899 579           delete_reflist( aTHX_ decode_state );
900              
901 579 100         if (NULL != decode_state->tag_handler) {
902 102           SvREFCNT_dec((SV *) decode_state->tag_handler);
903 102           decode_state->tag_handler = NULL;
904             }
905              
906 579           Safefree(decode_state);
907 579           }
908              
909 590           SV *cbf_decode_document( pTHX_ decode_ctx *decode_state ) {
910 590           SV *RETVAL = cbf_decode_one( aTHX_ decode_state );
911              
912 530 100         if (decode_state->incomplete_by) {
913 146           _croak_incomplete( aTHX_ decode_state );
914             }
915              
916 384 100         if (decode_state->curbyte != decode_state->end) {
917 1           STRLEN bytes_count = decode_state->end - decode_state->curbyte;
918              
919             char numstr[24];
920 1           _uv_to_str(bytes_count, numstr, 24);
921              
922 1           char * words[2] = { numstr, NULL };
923              
924 1           call_argv("CBOR::Free::_warn_decode_leftover", G_DISCARD, words);
925             }
926              
927 384           return RETVAL;
928             }
929              
930 463           SV *cbf_decode( pTHX_ SV *cbor, HV *tag_handler, UV flags ) {
931              
932 463           decode_ctx *decode_state = create_decode_state( aTHX_ cbor, tag_handler, flags);
933              
934 463           SV *RETVAL = cbf_decode_document( aTHX_ decode_state );
935              
936 268           free_decode_state( aTHX_ decode_state);
937              
938 268           return RETVAL;
939             }