File Coverage

Free.xs
Criterion Covered Total %
statement 128 131 97.7
branch 92 206 44.6
condition n/a
subroutine n/a
pod n/a
total 220 337 65.2


line stmt bran cond sub pod time code
1             #include "easyxs/init.h"
2              
3             #include
4             #include
5             #include
6              
7             #include "cbor_free_common.h"
8              
9             #include "cbor_free_boolean.h"
10             #include "cbor_free_encode.h"
11             #include "cbor_free_decode.h"
12              
13             #define _PACKAGE "CBOR::Free"
14              
15             #define CANONICAL_OPT "canonical"
16             #define PRESERVE_REFS_OPT "preserve_references"
17             #define SCALAR_REFS_OPT "scalar_references"
18             #define STRING_ENCODE_MODE_OPT "string_encode_mode"
19              
20             #define UNUSED(x) (void)(x)
21              
22             const char* const cbf_string_encode_mode_options[] = {
23             "sv",
24             "encode_text",
25             "as_text",
26             "as_binary",
27             };
28              
29             HV *cbf_stash = NULL;
30              
31 33           SV* _seqdecode_get( pTHX_ seqdecode_ctx* seqdecode) {
32 33           decode_ctx* decode_state = seqdecode->decode_state;
33              
34 33           decode_state->curbyte = decode_state->start;
35              
36 33 100         if (decode_state->flags & CBF_FLAG_PRESERVE_REFERENCES) {
37 2           reset_reflist_if_needed(aTHX_ decode_state);
38             }
39              
40 33           SV *referent = cbf_decode_one( aTHX_ seqdecode->decode_state );
41              
42 33 100         if (seqdecode->decode_state->incomplete_by) {
43 15           seqdecode->decode_state->incomplete_by = 0;
44 15           return &PL_sv_undef;
45             }
46              
47             // TODO: Once the lead offset gets big enough,
48             // recreate this buffer.
49 18           sv_chop( seqdecode->cbor, decode_state->curbyte );
50              
51 18           advance_decode_state_buffer( aTHX_ decode_state );
52              
53 18           return newRV_noinc(referent);
54             }
55              
56 9           bool _handle_flag_call( pTHX_ decode_ctx* decode_state, SV* new_setting, U8 flagval ) {
57 9 100         if (new_setting == NULL || SvTRUE(new_setting)) {
    50          
    50          
    0          
    50          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    0          
    50          
    0          
58 5           decode_state->flags |= flagval;
59             }
60             else {
61 4           decode_state->flags &= ~flagval;
62             }
63              
64 9           return( !!(decode_state->flags & flagval) );
65             }
66              
67 116           SV * _bless_to_sv( pTHX_ SV *class, void* ptr ) {
68 116           SV *RETVAL = newSV(0);
69 116 50         sv_setref_pv(RETVAL, SvPV_nolen(class), ptr);
70              
71 116           return RETVAL;
72             }
73              
74 6           static inline void * sv_to_ptr( pTHX_ SV *self) {
75 6 50         IV tmp = SvIV((SV*)SvRV(self));
76 6           return INT2PTR(void*, tmp);
77             }
78              
79 3           static inline SV* _set_string_decode( pTHX_ SV* self, enum cbf_string_decode_mode new_setting ) {
80 3           decode_ctx* decode_state = (decode_ctx*) sv_to_ptr(aTHX_ self);
81 3           decode_state->string_decode_mode = new_setting;
82              
83 3 50         return (GIMME_V == G_VOID) ? NULL : newSVsv(self);
    50          
84             }
85              
86 3           static inline SV* _seq_set_string_decode( pTHX_ SV* self, enum cbf_string_decode_mode new_setting ) {
87 3           seqdecode_ctx* seqdecode = (seqdecode_ctx*) sv_to_ptr(aTHX_ self);
88 3           seqdecode->decode_state->string_decode_mode = new_setting;
89              
90 3 50         return (GIMME_V == G_VOID) ? NULL : newSVsv(self);
    50          
91             }
92              
93 6           static inline bool _handle_preserve_references( pTHX_ decode_ctx* decode_state, SV* new_setting ) {
94 6           bool RETVAL = _handle_flag_call( aTHX_ decode_state, new_setting, CBF_FLAG_PRESERVE_REFERENCES );
95              
96 6 100         if (RETVAL) {
97 2           ensure_reflist_exists( aTHX_ decode_state );
98             }
99 4 100         else if (NULL != decode_state->reflist) {
100 2           delete_reflist( aTHX_ decode_state );
101             }
102              
103 6           return RETVAL;
104             }
105              
106 103           static inline void _set_tag_handlers( pTHX_ decode_ctx* decode_state, U8 items_len, SV** args ) {
107 103 50         if (!(items_len % 2)) {
108 0           croak("Odd key-value pair given!");
109             }
110              
111 103 100         if (NULL == decode_state->tag_handler) {
112 102           decode_state->tag_handler = newHV();
113             }
114              
115             U8 i;
116 206 100         for (i=1; i
117 103           HV* tag_handler = decode_state->tag_handler;
118              
119 103           SV* tagnum_sv = args[i];
120 103 50         UV tagnum = SvUV(tagnum_sv);
121              
122 103           i++;
123 103 50         if (i
124 103           SV* tagcb_sv = args[i];
125              
126 103           hv_store(
127             tag_handler,
128             (const char *) &tagnum,
129             sizeof(UV),
130             tagcb_sv,
131             0
132             );
133              
134 103           SvREFCNT_inc(tagcb_sv);
135             }
136             }
137 103           }
138              
139             //----------------------------------------------------------------------
140             //----------------------------------------------------------------------
141              
142             MODULE = CBOR::Free PACKAGE = CBOR::Free
143              
144             PROTOTYPES: DISABLE
145              
146             BOOT:
147 26           cbf_stash = gv_stashpv(_PACKAGE, FALSE);
148 26           newCONSTSUB(cbf_stash, "_MAX_RECURSION", newSVuv( MAX_ENCODE_RECURSE ));
149              
150              
151             SV *
152             encode( SV * value, ... )
153             CODE:
154 16967           uint8_t encode_state_flags = 0;
155 16967           enum cbf_string_encode_mode string_encode_mode = CBF_STRING_ENCODE_SV;
156              
157             U8 i;
158             char* optname;
159             SV* opt_sv;
160              
161 17118 100         for (i=1; i
162 151 50         if (!(i % 2)) continue;
163              
164 151           opt_sv = ST(i);
165 151 50         if (!SvPOK(opt_sv)) continue;
166              
167 151           optname = SvPVX(opt_sv);
168              
169 151 100         if (strEQ(optname, STRING_ENCODE_MODE_OPT)) {
170 71           ++i;
171              
172 71 50         if (i
173 71           SV* opt = ST(i);
174              
175 71 50         if (SvOK(opt)) {
    0          
    0          
176 71 50         char* optstr = SvPV_nolen(opt);
177              
178             U8 i;
179 204 50         for (i=0; i
180 204 100         if (strEQ(optstr, cbf_string_encode_mode_options[i])) {
181 71           string_encode_mode = i;
182 71           break;
183             }
184             }
185              
186 71 50         if (i == CBF_STRING_ENCODE__LIMIT) {
187 71           croak("Invalid " STRING_ENCODE_MODE_OPT ": %s", optstr);
188             }
189             }
190              
191             }
192             }
193              
194 80 100         else if (strEQ(optname, CANONICAL_OPT)) {
195 72           ++i;
196 72 50         if (i
    50          
    50          
    50          
    0          
    0          
    100          
    50          
    50          
    50          
    100          
    50          
    50          
    100          
    50          
    0          
    100          
197 72           encode_state_flags |= ENCODE_FLAG_CANONICAL;
198             }
199             }
200              
201 8 100         else if (strEQ(optname, PRESERVE_REFS_OPT)) {
202 2           ++i;
203 2 50         if (i
    50          
    50          
    50          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    0          
    0          
    50          
204 2           encode_state_flags |= ENCODE_FLAG_PRESERVE_REFS;
205             }
206             }
207              
208 6 50         else if (strEQ(optname, SCALAR_REFS_OPT)) {
209 6           ++i;
210 6 50         if (i
    50          
    50          
    50          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    50          
    50          
    100          
    50          
    0          
    100          
211 6           encode_state_flags |= ENCODE_FLAG_SCALAR_REFS;
212             }
213             }
214              
215             else {
216 0           warn("Invalid option: %s", optname);
217             }
218             }
219              
220 16967           encode_ctx encode_state = cbf_encode_ctx_create(encode_state_flags, string_encode_mode);
221              
222 16967           RETVAL = newSV(0);
223              
224 16967           cbf_encode(aTHX_ value, &encode_state, RETVAL);
225              
226 16951           cbf_encode_ctx_free_reftracker( &encode_state );
227              
228             // Don’t use newSVpvn here because that will copy the string.
229             // Instead, create a new SV and manually assign its pieces.
230             // This follows the example from ext/POSIX/POSIX.xs:
231              
232 16951 50         SvUPGRADE(RETVAL, SVt_PV);
233 16951           SvPV_set(RETVAL, encode_state.buffer);
234 16951           SvPOK_on(RETVAL);
235 16951           SvCUR_set(RETVAL, encode_state.len - 1);
236 16951           SvLEN_set(RETVAL, encode_state.buflen);
237              
238             OUTPUT:
239             RETVAL
240              
241              
242             SV *
243             decode( SV *cbor )
244             CODE:
245 463           RETVAL = cbf_decode( aTHX_ cbor, NULL, false );
246              
247             OUTPUT:
248             RETVAL
249              
250             # ----------------------------------------------------------------------
251              
252             MODULE = CBOR::Free PACKAGE = CBOR::Free::Decoder
253              
254             PROTOTYPES: DISABLE
255              
256             SV*
257             new(SV *class)
258             CODE:
259 107           decode_ctx* decode_state = create_decode_state( aTHX_ NULL, NULL, CBF_FLAG_PERSIST_STATE);
260              
261 107           RETVAL = _bless_to_sv( aTHX_ class, (void*)decode_state);
262              
263             OUTPUT:
264             RETVAL
265              
266             SV*
267             decode(decode_ctx* decode_state, SV* cbor)
268             CODE:
269 127           decode_state->curbyte = 0;
270 127           renew_decode_state_buffer( aTHX_ decode_state, cbor );
271              
272 127 100         if (decode_state->flags & CBF_FLAG_PRESERVE_REFERENCES) {
273 2           reset_reflist_if_needed(aTHX_ decode_state);
274             }
275              
276 127           RETVAL = cbf_decode_document( aTHX_ decode_state );
277              
278             OUTPUT:
279             RETVAL
280              
281             bool
282             preserve_references(decode_ctx* decode_state, SV* new_setting = NULL)
283             CODE:
284 3           RETVAL = _handle_preserve_references( aTHX_ decode_state, new_setting );
285              
286             OUTPUT:
287             RETVAL
288              
289             bool
290             naive_utf8(decode_ctx* decode_state, SV* new_setting = NULL)
291             CODE:
292 2           RETVAL = _handle_flag_call( aTHX_ decode_state, new_setting, CBF_FLAG_NAIVE_UTF8 );
293              
294             OUTPUT:
295             RETVAL
296              
297             SV *
298             string_decode_cbor(SV* self)
299             CODE:
300 1           RETVAL = _set_string_decode( aTHX_ self, CBF_STRING_DECODE_CBOR );
301              
302             OUTPUT:
303             RETVAL
304              
305             SV *
306             string_decode_never(SV* self)
307             CODE:
308 1           RETVAL = _set_string_decode( aTHX_ self, CBF_STRING_DECODE_NEVER );
309              
310             OUTPUT:
311             RETVAL
312              
313             SV *
314             string_decode_always(SV* self)
315             CODE:
316 1           RETVAL = _set_string_decode( aTHX_ self, CBF_STRING_DECODE_ALWAYS );
317              
318             OUTPUT:
319             RETVAL
320              
321             void
322             _set_tag_handlers_backend(decode_ctx* decode_state, ...)
323             CODE:
324 103           _set_tag_handlers( aTHX_ decode_state, items, &ST(0) );
325              
326             void
327             DESTROY(decode_ctx* decode_state)
328             CODE:
329 107           free_decode_state( aTHX_ decode_state);
330              
331              
332             # ----------------------------------------------------------------------
333              
334             MODULE = CBOR::Free PACKAGE = CBOR::Free::SequenceDecoder
335              
336             PROTOTYPES: DISABLE
337              
338             SV *
339             new(SV *class)
340             CODE:
341              
342 9           SV* cbor = newSVpvs("");
343              
344 9           decode_ctx* decode_state = create_decode_state( aTHX_ cbor, NULL, CBF_FLAG_PERSIST_STATE);
345              
346             seqdecode_ctx* seqdecode;
347              
348 9           Newx( seqdecode, 1, seqdecode_ctx );
349              
350 9           seqdecode->decode_state = decode_state;
351 9           seqdecode->cbor = cbor;
352              
353 9           RETVAL = _bless_to_sv( aTHX_ class, (void*)seqdecode);
354              
355             OUTPUT:
356             RETVAL
357              
358             SV *
359             give(seqdecode_ctx* seqdecode, SV* addend)
360             CODE:
361 30           sv_catsv( seqdecode->cbor, addend );
362              
363 30           renew_decode_state_buffer( aTHX_ seqdecode->decode_state, seqdecode->cbor );
364              
365 30           RETVAL = _seqdecode_get( aTHX_ seqdecode);
366              
367             OUTPUT:
368             RETVAL
369              
370             SV *
371             get(seqdecode_ctx* seqdecode)
372             CODE:
373 3           RETVAL = _seqdecode_get( aTHX_ seqdecode);
374              
375             OUTPUT:
376             RETVAL
377              
378             bool
379             preserve_references(seqdecode_ctx* seqdecode, SV* new_setting = NULL)
380             CODE:
381 3           RETVAL = _handle_preserve_references( aTHX_ seqdecode->decode_state, new_setting );
382              
383             OUTPUT:
384             RETVAL
385              
386             bool
387             naive_utf8(seqdecode_ctx* seqdecode, SV* new_setting = NULL)
388             CODE:
389 1           RETVAL = _handle_flag_call( aTHX_ seqdecode->decode_state, new_setting, CBF_FLAG_NAIVE_UTF8 );
390              
391             OUTPUT:
392             RETVAL
393              
394              
395             SV *
396             string_decode_cbor(SV* self)
397             CODE:
398 1           RETVAL = _seq_set_string_decode( aTHX_ self, CBF_STRING_DECODE_CBOR );
399              
400             OUTPUT:
401             RETVAL
402              
403             SV *
404             string_decode_never(SV* self)
405             CODE:
406 1           RETVAL = _seq_set_string_decode( aTHX_ self, CBF_STRING_DECODE_NEVER );
407              
408             OUTPUT:
409             RETVAL
410              
411             SV *
412             string_decode_always(SV* self)
413             CODE:
414 1           RETVAL = _seq_set_string_decode( aTHX_ self, CBF_STRING_DECODE_ALWAYS );
415              
416             OUTPUT:
417             RETVAL
418              
419             void
420             _set_tag_handlers_backend(seqdecode_ctx* seqdecode, ...)
421             CODE:
422 0           _set_tag_handlers( aTHX_ seqdecode->decode_state, items, &ST(0) );
423              
424             void
425             DESTROY(seqdecode_ctx* seqdecode)
426             CODE:
427 9           free_decode_state( aTHX_ seqdecode->decode_state);
428 9           SvREFCNT_dec(seqdecode->cbor);
429              
430 9           Safefree(seqdecode);