File Coverage

decode.c
Criterion Covered Total %
statement 249 274 90.8
branch 59 82 71.9
condition n/a
subroutine n/a
pod n/a
total 308 356 86.5


line stmt bran cond sub pod time code
1             #define PERL_NO_GET_CONTEXT
2             #include "EXTERN.h"
3             #include "perl.h"
4             #include "XSUB.h"
5              
6             #include
7             #include "define.h"
8             #include "cc_bignum.h"
9             #include "proto.h"
10             #include "swap.h"
11             #include "decode.h"
12              
13             #ifdef CAN_64BIT
14             static void decode_bigint (pTHX_ unsigned char *input, STRLEN len, struct cc_type *type, SV *output);
15             #endif
16             static void decode_blob (pTHX_ unsigned char *input, STRLEN len, struct cc_type *type, SV *output);
17             static void decode_boolean (pTHX_ unsigned char *input, STRLEN len, struct cc_type *type, SV *output);
18             static void decode_date (pTHX_ unsigned char *input, STRLEN len, struct cc_type *type, SV *output);
19             static void decode_decimal (pTHX_ unsigned char *input, STRLEN len, struct cc_type *type, SV *output);
20             static void decode_double (pTHX_ unsigned char *input, STRLEN len, struct cc_type *type, SV *output);
21             static void decode_float (pTHX_ unsigned char *input, STRLEN len, struct cc_type *type, SV *output);
22             static void decode_inet (pTHX_ unsigned char *input, STRLEN len, struct cc_type *type, SV *output);
23             static void decode_int (pTHX_ unsigned char *input, STRLEN len, struct cc_type *type, SV *output);
24             static void decode_list (pTHX_ unsigned char *input, STRLEN len, struct cc_type *type, SV *output);
25             static void decode_map (pTHX_ unsigned char *input, STRLEN len, struct cc_type *type, SV *output);
26             static void decode_smallint(pTHX_ unsigned char *input, STRLEN len, struct cc_type *type, SV *output);
27             static void decode_time (pTHX_ unsigned char *input, STRLEN len, struct cc_type *type, SV *output);
28             static void decode_tinyint (pTHX_ unsigned char *input, STRLEN len, struct cc_type *type, SV *output);
29             static void decode_tuple (pTHX_ unsigned char *input, STRLEN len, struct cc_type *type, SV *output);
30             static void decode_udt (pTHX_ unsigned char *input, STRLEN len, struct cc_type *type, SV *output);
31             static void decode_utf8 (pTHX_ unsigned char *input, STRLEN len, struct cc_type *type, SV *output);
32             static void decode_uuid (pTHX_ unsigned char *input, STRLEN len, struct cc_type *type, SV *output);
33             static void decode_varint (pTHX_ unsigned char *input, STRLEN len, struct cc_type *type, SV *output);
34              
35 282           void decode_cell(pTHX_ unsigned char *input, STRLEN len, STRLEN *pos, struct cc_type *type, SV *output)
36             {
37             unsigned char *bytes;
38             STRLEN bytes_len;
39              
40 282 100         if (unpack_bytes(aTHX_ input, len, pos, &bytes, &bytes_len) != 0) {
41 17           sv_setsv(output, &PL_sv_undef);
42 17           return;
43             }
44              
45 265           switch (type->type_id) {
46 10           case CC_TYPE_ASCII:
47             case CC_TYPE_CUSTOM:
48             case CC_TYPE_BLOB:
49 10           decode_blob(aTHX_ bytes, bytes_len, type, output);
50 10           break;
51              
52 14           case CC_TYPE_BOOLEAN:
53 14           decode_boolean(aTHX_ bytes, bytes_len, type, output);
54 14           break;
55              
56 4           case CC_TYPE_VARCHAR:
57             case CC_TYPE_TEXT:
58 4           decode_utf8(aTHX_ bytes, bytes_len, type, output);
59 4           break;
60              
61 11           case CC_TYPE_INET:
62 11           decode_inet(aTHX_ bytes, bytes_len, type, output);
63 11           break;
64              
65 8           case CC_TYPE_SET:
66             case CC_TYPE_LIST:
67 8           decode_list(aTHX_ bytes, bytes_len, type, output);
68 8           break;
69              
70 3           case CC_TYPE_UUID:
71             case CC_TYPE_TIMEUUID:
72 3           decode_uuid(aTHX_ bytes, bytes_len, type, output);
73 3           break;
74              
75 4           case CC_TYPE_FLOAT:
76 4           decode_float(aTHX_ bytes, bytes_len, type, output);
77 4           break;
78              
79 4           case CC_TYPE_DOUBLE:
80 4           decode_double(aTHX_ bytes, bytes_len, type, output);
81 4           break;
82              
83 6           case CC_TYPE_DECIMAL:
84 6           decode_decimal(aTHX_ bytes, bytes_len, type, output);
85 6           break;
86              
87 82           case CC_TYPE_VARINT:
88             case CC_TYPE_BIGINT:
89             case CC_TYPE_COUNTER:
90             case CC_TYPE_TIMESTAMP:
91             case CC_TYPE_SMALLINT:
92             case CC_TYPE_TINYINT:
93             case CC_TYPE_INT:
94 82           decode_varint(aTHX_ bytes, bytes_len, type, output);
95 82           break;
96              
97 64           case CC_TYPE_DATE:
98 64           decode_date(aTHX_ bytes, bytes_len, type, output);
99 64           break;
100              
101 48           case CC_TYPE_TIME:
102 48           decode_time(aTHX_ bytes, bytes_len, type, output);
103 48           break;
104              
105 4           case CC_TYPE_MAP:
106 4           decode_map(aTHX_ bytes, bytes_len, type, output);
107 4           break;
108              
109 1           case CC_TYPE_UDT:
110 1           decode_udt(aTHX_ bytes, bytes_len, type, output);
111 1           break;
112              
113 2           case CC_TYPE_TUPLE:
114 2           decode_tuple(aTHX_ bytes, bytes_len, type, output);
115 2           break;
116              
117 0           default:
118 0           sv_setsv(output, &PL_sv_undef);
119 0           warn("Decoder doesn't yet understand type %d, returning undef instead", type->type_id);
120 0           break;
121             }
122             }
123              
124             #ifdef CAN_64BIT
125 15           void decode_bigint(pTHX_ unsigned char *input, STRLEN len, struct cc_type *type, SV *output)
126             {
127             union {
128             unsigned char bytes[8];
129             int64_t bigint;
130             } bytes_or_bigint;
131              
132 15 50         if (UNLIKELY(len != 8))
133 0           croak("decode_bigint: len != 8");
134              
135 15           memcpy(bytes_or_bigint.bytes, input, 8);
136 15           bswap8(bytes_or_bigint.bytes);
137 15           sv_setiv(output, bytes_or_bigint.bigint);
138 15           }
139             #endif
140              
141 10           void decode_blob(pTHX_ unsigned char *input, STRLEN len, struct cc_type *type, SV *output)
142             {
143 10           sv_setpvn(output, (char*)input, len);
144 10           }
145              
146 4           void decode_double(pTHX_ unsigned char *input, STRLEN len, struct cc_type *type, SV *output)
147             {
148             union {
149             unsigned char bytes[8];
150             double doub;
151             } bytes_or_double;
152              
153 4 50         if (UNLIKELY(len != 8))
154 0           croak("decode_double: len != 8");
155              
156 4           memcpy(bytes_or_double.bytes, input, 8);
157 4           bswap8(bytes_or_double.bytes);
158 4           sv_setnv(output, bytes_or_double.doub);
159 4           }
160              
161 4           void decode_float(pTHX_ unsigned char *input, STRLEN len, struct cc_type *type, SV *output)
162             {
163             union {
164             unsigned char bytes[4];
165             float fl;
166             } bytes_or_float;
167              
168 4 50         if (UNLIKELY(len != 4))
169 0           croak("decode_float: len != 4");
170              
171 4           memcpy(bytes_or_float.bytes, input, 4);
172 4           bswap4(bytes_or_float.bytes);
173 4           sv_setnv(output, bytes_or_float.fl);
174 4           }
175              
176 34           void decode_int(pTHX_ unsigned char *input, STRLEN len, struct cc_type *type, SV *output)
177             {
178             union {
179             unsigned char bytes[4];
180             int32_t i;
181             } bytes_or_int;
182              
183 34 50         if (UNLIKELY(len != 4))
184 0           croak("decode_int: len != 4");
185              
186 34           memcpy(bytes_or_int.bytes, input, 4);
187 34           bswap4(bytes_or_int.bytes);
188 34           sv_setiv(output, bytes_or_int.i);
189 34           }
190              
191 15           void decode_smallint(pTHX_ unsigned char *input, STRLEN len, struct cc_type *type, SV *output)
192             {
193             union {
194             unsigned char bytes[2];
195             int16_t i;
196             } bytes_or_smallint;
197              
198 15 50         if (UNLIKELY(len != 2))
199 0           croak("decode_smallint: len != 2");
200              
201 15           memcpy(bytes_or_smallint.bytes, input, 2);
202 15           bswap2(bytes_or_smallint.bytes);
203 15           sv_setiv(output, bytes_or_smallint.i);
204 15           }
205              
206 20           void decode_tinyint(pTHX_ unsigned char *input, STRLEN len, struct cc_type *type, SV *output)
207             {
208 20 50         if (UNLIKELY(len != 1))
209 0           croak("decode_tinyint: len != 1");
210              
211 20           int8_t number = *input;
212 20           sv_setiv(output, number);
213 20           }
214              
215 4           void decode_utf8(pTHX_ unsigned char *input, STRLEN len, struct cc_type *type, SV *output)
216             {
217 4           sv_setpvn(output, (char*)input, len);
218 4           SvUTF8_on(output);
219 4           }
220              
221 14           void decode_boolean(pTHX_ unsigned char *input, STRLEN len, struct cc_type *type, SV *output)
222             {
223 14 50         if (UNLIKELY(len != 1))
224 0           croak("decode_boolean: len != 1");
225              
226 14 100         if (*input)
227 9           sv_setsv(output, &PL_sv_yes);
228             else
229 5           sv_setsv(output, &PL_sv_no);
230 14           }
231              
232 11           void decode_inet(pTHX_ unsigned char *input, STRLEN len, struct cc_type *type, SV *output)
233             {
234 11 100         if (len == 4) {
235             char str[INET_ADDRSTRLEN];
236 3           inet_ntop(AF_INET, (char*)input, str, INET_ADDRSTRLEN);
237 3           sv_setpv(output, str);
238              
239 8 50         } else if (len == 16) {
240             char str[INET6_ADDRSTRLEN];
241 8           inet_ntop(AF_INET6, (char*)input, str, INET6_ADDRSTRLEN);
242 8           sv_setpv(output, str);
243              
244             } else {
245 0           croak("decode_inet: len != (4|16)");
246             }
247 11           }
248              
249 8           void decode_list(pTHX_ unsigned char *input, STRLEN len, struct cc_type *type, SV *output)
250             {
251             struct cc_type *inner_type;
252             int i;
253             AV *the_list;
254             SV *the_rv;
255             STRLEN pos;
256              
257 8           inner_type = type->inner_type;
258             assert(inner_type);
259              
260 8 50         if (UNLIKELY(len < 4))
261 0           croak("decode_list: len < 4");
262              
263 8           int32_t num_elements = (int32_t)ntohl(*(uint32_t*)(input));
264 8 50         if (UNLIKELY(num_elements < 0))
265 0           croak("decode_list: num_elements < 0");
266              
267 8           the_list = newAV();
268 8           the_rv = newRV_noinc((SV*)the_list);
269 8           sv_setsv(output, the_rv);
270 8           SvREFCNT_dec(the_rv);
271              
272 8           pos = 4;
273              
274 24 100         for (i = 0; i < num_elements; i++) {
275 16           SV *decoded = newSV(0);
276 16           av_push(the_list, decoded);
277              
278 16           decode_cell(aTHX_ input, len, &pos, inner_type, decoded);
279             }
280 8           }
281              
282 3           void decode_uuid(pTHX_ unsigned char *input, STRLEN len, struct cc_type *type, SV *output)
283             {
284 3 50         if (UNLIKELY(len != 16))
285 0           croak("decode_uuid: len != 16");
286              
287 3           sv_setpvf(output, "%.2x%.2x%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x%.2x%.2x%.2x%.2x",
288             input[0], input[1], input[2], input[3],
289             input[4], input[5], input[6], input[7],
290             input[8], input[9], input[10], input[11],
291             input[12], input[13], input[14], input[15]);
292 3           }
293              
294 6           void decode_decimal(pTHX_ unsigned char *input, STRLEN len, struct cc_type *type, SV *output)
295             {
296             union {
297             unsigned char bytes[4];
298             int32_t scale;
299             } bytes_or_scale;
300              
301 6 50         if (UNLIKELY(len < 5))
302 0           croak("decode_decimal: len < 5");
303              
304 6           memcpy(bytes_or_scale.bytes, input, 4);
305 6           bswap4(bytes_or_scale.bytes);
306 6           bytes_or_scale.scale *= -1;
307              
308 6           decode_varint(aTHX_ input+4, len-4, type, output);
309 6 100         if (bytes_or_scale.scale != 0) {
310             char *sign;
311 3 100         if (bytes_or_scale.scale > 0) {
312 2           sign = "+";
313             } else {
314 1           sign = "";
315             }
316 3           sv_catpvf(output, "e%s%d", sign, bytes_or_scale.scale);
317             }
318 6           }
319              
320 88           void decode_varint(pTHX_ unsigned char *input, STRLEN len, struct cc_type *type, SV *output)
321             {
322 88 50         if (UNLIKELY(len <= 0)) {
323 0           croak("decode_varint: len <= 0");
324 88 100         } else if (len == 1) {
325 20           decode_tinyint(aTHX_ input, len, type, output);
326 68 100         } else if (len == 2) {
327 15           decode_smallint(aTHX_ input, len, type, output);
328 53 100         } else if (len == 3) {
329             unsigned char bytes[4];
330 2           memcpy(bytes+1, input, 3);
331 2 100         if (input[0] & 0x80) {
332 1           bytes[0] = 0xff;
333             } else {
334 1           bytes[0] = 0;
335             }
336 2           decode_int(aTHX_ bytes, 4, type, output);
337 51 100         } else if (len == 4) {
338 32           decode_int(aTHX_ input, len, type, output);
339             #ifdef CAN_64BIT
340 19 100         } else if (len < 8) {
341             unsigned char bytes[8];
342 1 50         memset(bytes, (input[0] & 0x80) ? 0xff : 0, 8);
343 1           memcpy(bytes+8-len, input, len);
344 1           decode_bigint(aTHX_ bytes, 8, type, output);
345 18 100         } else if (len == 8) {
346 14           decode_bigint(aTHX_ input, len, type, output);
347             #endif
348             } else {
349             unsigned char *tmp;
350             char *tmpout;
351             struct cc_bignum bn;
352             int i;
353              
354 4           Newxz(tmpout, (len*4)+2, char);
355              
356 4           Newxz(tmp, len, unsigned char);
357 69 100         for (i = 0; i < len; i++) {
358 65           tmp[len-i-1] = (unsigned char)input[i];
359             }
360              
361 4           cc_bignum_init_bytes(&bn, tmp, len);
362              
363 4           cc_bignum_stringify(&bn, tmpout, (len*4)+2);
364 4           sv_setpv(output, tmpout);
365              
366 4           cc_bignum_destroy(&bn);
367 4           Safefree(tmp);
368 4           Safefree(tmpout);
369             }
370 88           }
371              
372             /* fun fact: fmod() doesn't actually implement the modulo operation... */
373 192           double fmod_properly(double x, double y)
374             {
375 192           double mod = fmod(x, y);
376 192 50         if (mod < 0)
377 0           mod += y;
378 192           return mod;
379             }
380              
381 64           void decode_date(pTHX_ unsigned char *input, STRLEN len, struct cc_type *type, SV *output)
382             {
383             uint32_t ind;
384             double f, e, J, h, g, Y, M, D;
385              
386 64 50         if (UNLIKELY(len != 4))
387 0           croak("decode_date: len != 4");
388              
389 64           ind = ntohl(*(uint32_t*)input);
390              
391             /* This is why unit tests exist. :-) */
392 64           J = ind;
393 64           J -= 0x80000000 - 2440588;
394              
395 64           f = J + 1401 + floor((floor((4 * J + 274277) / 146097) * 3) / 4) - 38;
396 64           e = (4 * f) + 3;
397 64           g = floor(fmod_properly(e, 1461) / 4);
398 64           h = 5 * g + 2;
399 64           D = floor(fmod_properly(h, 153) / 5) + 1;
400 64           M = fmod_properly((floor(h / 153) + 2), 12) + 1;
401 64           Y = floor(e / 1461) - 4716 + floor((12 + 2 - M) / 12);
402              
403 64           sv_setpvf(output, "%.0lf-%02.0lf-%02.0lf", Y, M, D);
404 64           }
405              
406             #ifdef CAN_64BIT
407 48           void decode_time(pTHX_ unsigned char *input, STRLEN len, struct cc_type *type, SV *output)
408             {
409             int64_t nano, seconds, hours, minutes;
410             STRLEN pvlen;
411             char *result;
412              
413             union {
414             unsigned char bytes[8];
415             int64_t bigint;
416             } bytes_or_bigint;
417              
418 48 50         if (UNLIKELY(len != 8))
419 0           croak("decode_time: len != 8");
420              
421 48           memcpy(bytes_or_bigint.bytes, input, 8);
422 48           bswap8(bytes_or_bigint.bytes);
423              
424 48 50         if (UNLIKELY(bytes_or_bigint.bigint < 0 || bytes_or_bigint.bigint > 86399999999999))
    50          
425 0           croak("decode_time: invalid value");
426              
427 48           nano = bytes_or_bigint.bigint % 1000000000;
428 48           seconds = bytes_or_bigint.bigint / 1000000000;
429 48           hours = seconds / 3600;
430 48           minutes = (seconds % 3600) / 60;
431 48           seconds = seconds % 60;
432              
433 48           sv_setpvf(output, "%lld:%.2lld:%.2lld.%lld", hours, minutes, seconds, nano);
434 48           result = SvPV(output, pvlen);
435 144 100         while (result[pvlen-1] == '0')
436 96           pvlen--;
437 48 50         if (result[pvlen-1] == '.')
438 0           pvlen--;
439 48           SvCUR_set(output, pvlen);
440 48           }
441             #else
442             /* 32bit compat */
443             void decode_time(pTHX_ unsigned char *input, STRLEN len, struct cc_type *type, SV *output)
444             {
445             int32_t nano, seconds, hours, minutes;
446             char *txt;
447             char workbuf[20];
448             STRLEN txt_len;
449              
450             decode_varint(aTHX_ input, len, type, output);
451             /* output now contains a string represending the ns since midnight */
452              
453             txt = SvPV(output, txt_len);
454             if (txt_len > 14) {
455             croak("decode_time: invalid value");
456             }
457              
458             if (txt_len <= 9) {
459             memset(workbuf, 0, 20);
460             memcpy(workbuf, txt, txt_len);
461             seconds = 0;
462             nano = atoi(workbuf);
463             } else {
464             memset(workbuf, 0, 20);
465             memcpy(workbuf, txt+txt_len-9, 9);
466             nano = atoi(workbuf);
467             memset(workbuf, 0, 20);
468             memcpy(workbuf, txt, txt_len-9);
469             seconds = atoi(workbuf);
470             }
471              
472             hours = seconds / 3600;
473             minutes = (seconds % 3600) / 60;
474             seconds = seconds % 60;
475              
476             sv_setpvf(output, "%d:%.2d:%.2d.%d", hours, minutes, seconds, nano);
477             txt = SvPV(output, txt_len);
478             while (txt[txt_len-1] == '0')
479             txt_len--;
480             if (txt[txt_len-1] == '.')
481             txt_len--;
482             SvCUR_set(output, txt_len);
483             }
484             #endif
485              
486 4           void decode_map(pTHX_ unsigned char *input, STRLEN len, struct cc_type *type, SV *output)
487             {
488             struct cc_type *key_type, *value_type;
489             int i;
490             STRLEN pos;
491             HV *the_map;
492             SV *the_rv;
493              
494 4           key_type = &type->inner_type[0];
495 4           value_type = &type->inner_type[1];
496             assert(key_type && value_type);
497              
498 4 50         if (UNLIKELY(len < 4))
499 0           croak("decode_map: len < 4");
500              
501 4           int32_t num_elements = (int32_t)ntohl(*(uint32_t*)(input));
502 4 50         if (UNLIKELY(num_elements < 0))
503 0           croak("decode_map: num_elements < 0");
504              
505 4           the_map = newHV();
506 4           the_rv = newRV_noinc((SV*)the_map);
507 4           sv_setsv(output, the_rv);
508 4           SvREFCNT_dec(the_rv);
509              
510 4           pos = 4;
511              
512 12 100         for (i = 0; i < num_elements; i++) {
513             SV *key, *value;
514              
515 8           key = newSV(0);
516 8           sv_2mortal(key);
517 8           decode_cell(aTHX_ input, len, &pos, key_type, key);
518              
519 8           value = newSV(0);
520 8           hv_store_ent(the_map, key, value, 0);
521              
522 8           decode_cell(aTHX_ input, len, &pos, value_type, value);
523             }
524 4           }
525              
526 1           void decode_udt(pTHX_ unsigned char *input, STRLEN len, struct cc_type *type, SV *output)
527             {
528             struct cc_udt *udt;
529             int i;
530             STRLEN pos;
531             HV *the_obj;
532             SV *the_rv;
533              
534 1           the_obj = newHV();
535 1           the_rv = newRV_noinc((SV*)the_obj);
536 1           sv_setsv(output, the_rv);
537 1           SvREFCNT_dec(the_rv);
538              
539 1           udt = type->udt;
540             assert(udt && udt->fields);
541              
542 1           pos = 0;
543              
544 2 100         for (i = 0; i < udt->field_count; i++) {
545 1 50         if (len == pos) {
546 0           break;
547             }
548              
549             struct cc_udt_field *field;
550             SV *value;
551              
552 1           field = &udt->fields[i];
553 1           value = newSV(0);
554              
555 1           hv_store_ent(the_obj, field->name, value, field->name_hash);
556              
557 1           decode_cell(aTHX_ input, len, &pos, &field->type, value);
558             }
559 1           }
560              
561 2           void decode_tuple(pTHX_ unsigned char *input, STRLEN len, struct cc_type *type, SV *output)
562             {
563             SV *the_rv;
564             AV *the_tuple;
565             struct cc_tuple *tuple;
566             int i;
567             STRLEN pos;
568              
569 2           the_tuple = newAV();
570 2           the_rv = newRV_noinc((SV*)the_tuple);
571 2           sv_setsv(output, the_rv);
572 2           SvREFCNT_dec(the_rv);
573              
574 2           tuple = type->tuple;
575             assert(tuple);
576              
577 2           pos = 0;
578              
579 6 100         for (i = 0; i < tuple->field_count; i++) {
580 4           struct cc_type *type = &tuple->fields[i];
581 4           SV *decoded = newSV(0);
582 4           av_push(the_tuple, decoded);
583              
584 4           decode_cell(aTHX_ input, len, &pos, type, decoded);
585             }
586 2           }