ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/CBOR-XS/XS.xs
(Generate patch)

Comparing CBOR-XS/XS.xs (file contents):
Revision 1.35 by root, Sat Nov 30 17:19:34 2013 UTC vs.
Revision 1.44 by root, Tue Feb 18 22:12:12 2014 UTC

7#include <stdlib.h> 7#include <stdlib.h>
8#include <stdio.h> 8#include <stdio.h>
9#include <limits.h> 9#include <limits.h>
10#include <float.h> 10#include <float.h>
11 11
12#define ECB_NO_THREADS 1
12#include "ecb.h" 13#include "ecb.h"
13 14
14// compatibility with perl <5.18 15// compatibility with perl <5.18
15#ifndef HvNAMELEN_get 16#ifndef HvNAMELEN_get
16# define HvNAMELEN_get(hv) strlen (HvNAME (hv)) 17# define HvNAMELEN_get(hv) strlen (HvNAME (hv))
97}; 98};
98 99
99#define F_SHRINK 0x00000001UL 100#define F_SHRINK 0x00000001UL
100#define F_ALLOW_UNKNOWN 0x00000002UL 101#define F_ALLOW_UNKNOWN 0x00000002UL
101#define F_ALLOW_SHARING 0x00000004UL 102#define F_ALLOW_SHARING 0x00000004UL
103#define F_ALLOW_CYCLES 0x00000008UL
102#define F_PACK_STRINGS 0x00000008UL 104#define F_PACK_STRINGS 0x00000010UL
105#define F_VALIDATE_UTF8 0x00000020UL
103 106
104#define INIT_SIZE 32 // initial scalar size to be allocated 107#define INIT_SIZE 32 // initial scalar size to be allocated
105 108
106#define SB do { 109#define SB do {
107#define SE } while (0) 110#define SE } while (0)
126typedef struct { 129typedef struct {
127 U32 flags; 130 U32 flags;
128 U32 max_depth; 131 U32 max_depth;
129 STRLEN max_size; 132 STRLEN max_size;
130 SV *filter; 133 SV *filter;
134
135 // for the incremental parser
136 STRLEN incr_pos; // the current offset into the text
137 STRLEN incr_need; // minimum bytes needed to decode
138 AV *incr_count; // for every nesting level, the number of outstanding values, or -1 for indef.
131} CBOR; 139} CBOR;
132 140
133ecb_inline void 141ecb_inline void
134cbor_init (CBOR *cbor) 142cbor_init (CBOR *cbor)
135{ 143{
139 147
140ecb_inline void 148ecb_inline void
141cbor_free (CBOR *cbor) 149cbor_free (CBOR *cbor)
142{ 150{
143 SvREFCNT_dec (cbor->filter); 151 SvREFCNT_dec (cbor->filter);
152 SvREFCNT_dec (cbor->incr_count);
144} 153}
145 154
146///////////////////////////////////////////////////////////////////////////// 155/////////////////////////////////////////////////////////////////////////////
147// utility functions 156// utility functions
148 157
228{ 237{
229 need (enc, 9); 238 need (enc, 9);
230 239
231 if (ecb_expect_true (len < LENGTH_EXT1)) 240 if (ecb_expect_true (len < LENGTH_EXT1))
232 *enc->cur++ = major | len; 241 *enc->cur++ = major | len;
233 else if (ecb_expect_true (len <= 0xff)) 242 else if (ecb_expect_true (len <= 0xffU))
234 { 243 {
235 *enc->cur++ = major | LENGTH_EXT1; 244 *enc->cur++ = major | LENGTH_EXT1;
236 *enc->cur++ = len; 245 *enc->cur++ = len;
237 } 246 }
238 else if (len <= 0xffff) 247 else if (len <= 0xffffU)
239 { 248 {
240 *enc->cur++ = major | LENGTH_EXT2; 249 *enc->cur++ = major | LENGTH_EXT2;
241 *enc->cur++ = len >> 8; 250 *enc->cur++ = len >> 8;
242 *enc->cur++ = len; 251 *enc->cur++ = len;
243 } 252 }
244 else if (len <= 0xffffffff) 253 else if (len <= 0xffffffffU)
245 { 254 {
246 *enc->cur++ = major | LENGTH_EXT4; 255 *enc->cur++ = major | LENGTH_EXT4;
247 *enc->cur++ = len >> 24; 256 *enc->cur++ = len >> 24;
248 *enc->cur++ = len >> 16; 257 *enc->cur++ = len >> 16;
249 *enc->cur++ = len >> 8; 258 *enc->cur++ = len >> 8;
627 U8 m = *dec->cur & MINOR_MASK; 636 U8 m = *dec->cur & MINOR_MASK;
628 ++dec->cur; 637 ++dec->cur;
629 638
630 if (ecb_expect_true (m < LENGTH_EXT1)) 639 if (ecb_expect_true (m < LENGTH_EXT1))
631 return m; 640 return m;
632 641 else if (ecb_expect_true (m == LENGTH_EXT1))
633 switch (m)
634 { 642 {
635 case LENGTH_EXT1:
636 WANT (1); 643 WANT (1);
637 dec->cur += 1; 644 dec->cur += 1;
638 return dec->cur[-1]; 645 return dec->cur[-1];
639 646 }
640 case LENGTH_EXT2: 647 else if (ecb_expect_true (m == LENGTH_EXT2))
648 {
641 WANT (2); 649 WANT (2);
642 dec->cur += 2; 650 dec->cur += 2;
643 return (((UV)dec->cur[-2]) << 8) 651 return (((UV)dec->cur[-2]) << 8)
644 | ((UV)dec->cur[-1]); 652 | ((UV)dec->cur[-1]);
645 653 }
646 case LENGTH_EXT4: 654 else if (ecb_expect_true (m == LENGTH_EXT4))
655 {
647 WANT (4); 656 WANT (4);
648 dec->cur += 4; 657 dec->cur += 4;
649 return (((UV)dec->cur[-4]) << 24) 658 return (((UV)dec->cur[-4]) << 24)
650 | (((UV)dec->cur[-3]) << 16) 659 | (((UV)dec->cur[-3]) << 16)
651 | (((UV)dec->cur[-2]) << 8) 660 | (((UV)dec->cur[-2]) << 8)
652 | ((UV)dec->cur[-1]); 661 | ((UV)dec->cur[-1]);
653 662 }
654 case LENGTH_EXT8: 663 else if (ecb_expect_true (m == LENGTH_EXT8))
664 {
655 WANT (8); 665 WANT (8);
656 dec->cur += 8; 666 dec->cur += 8;
657 667
658 return 668 return
659#if UVSIZE < 8 669#if UVSIZE < 8
660 0 670 0
661#else 671#else
662 (((UV)dec->cur[-8]) << 56) 672 (((UV)dec->cur[-8]) << 56)
663 | (((UV)dec->cur[-7]) << 48) 673 | (((UV)dec->cur[-7]) << 48)
664 | (((UV)dec->cur[-6]) << 40) 674 | (((UV)dec->cur[-6]) << 40)
665 | (((UV)dec->cur[-5]) << 32) 675 | (((UV)dec->cur[-5]) << 32)
666#endif 676#endif
667 | (((UV)dec->cur[-4]) << 24) 677 | (((UV)dec->cur[-4]) << 24)
668 | (((UV)dec->cur[-3]) << 16) 678 | (((UV)dec->cur[-3]) << 16)
669 | (((UV)dec->cur[-2]) << 8) 679 | (((UV)dec->cur[-2]) << 8)
670 | ((UV)dec->cur[-1]); 680 | ((UV)dec->cur[-1]);
671 681 }
672 default: 682 else
673 ERR ("corrupted CBOR data (unsupported integer minor encoding)"); 683 ERR ("corrupted CBOR data (unsupported integer minor encoding)");
674 }
675 684
676fail: 685fail:
677 return 0; 686 return 0;
678} 687}
679 688
705 } 714 }
706 else 715 else
707 { 716 {
708 int i, len = decode_uint (dec); 717 int i, len = decode_uint (dec);
709 718
719 WANT (len); // complexity check for av_fill - need at least one byte per value, do not allow supersize arrays
710 av_fill (av, len - 1); 720 av_fill (av, len - 1);
711 721
712 for (i = 0; i < len; ++i) 722 for (i = 0; i < len; ++i)
713 AvARRAY (av)[i] = decode_sv (dec); 723 AvARRAY (av)[i] = decode_sv (dec);
714 } 724 }
727{ 737{
728 // for speed reasons, we specialcase single-string 738 // for speed reasons, we specialcase single-string
729 // byte or utf-8 strings as keys, but only when !stringref 739 // byte or utf-8 strings as keys, but only when !stringref
730 740
731 if (ecb_expect_true (!dec->stringref)) 741 if (ecb_expect_true (!dec->stringref))
732 if ((*dec->cur - MAJOR_BYTES) <= 27) 742 if (ecb_expect_true ((U8)(*dec->cur - MAJOR_BYTES) <= LENGTH_EXT8))
733 { 743 {
734 I32 len = decode_uint (dec); 744 I32 len = decode_uint (dec);
735 char *key = (char *)dec->cur; 745 char *key = (char *)dec->cur;
736 746
737 dec->cur += len; 747 dec->cur += len;
738 748
739 if (ecb_expect_false (dec->stringref))
740 av_push (dec->stringref, newSVpvn (key, len));
741
742 hv_store (hv, key, len, decode_sv (dec), 0); 749 hv_store (hv, key, len, decode_sv (dec), 0);
743 750
744 return; 751 return;
745 } 752 }
746 else if ((*dec->cur - MAJOR_TEXT) <= 27) 753 else if (ecb_expect_true ((U8)(*dec->cur - MAJOR_TEXT) <= LENGTH_EXT8))
747 { 754 {
748 I32 len = decode_uint (dec); 755 I32 len = decode_uint (dec);
749 char *key = (char *)dec->cur; 756 char *key = (char *)dec->cur;
750 757
751 dec->cur += len; 758 dec->cur += len;
752 759
753 if (ecb_expect_false (dec->stringref)) 760 if (ecb_expect_false (dec->cbor.flags & F_VALIDATE_UTF8))
754 av_push (dec->stringref, newSVpvn_utf8 (key, len, 1)); 761 if (!is_utf8_string (key, len))
762 ERR ("corrupted CBOR data (invalid UTF-8 in map key)");
755 763
756 hv_store (hv, key, -len, decode_sv (dec), 0); 764 hv_store (hv, key, -len, decode_sv (dec), 0);
757 765
758 return; 766 return;
759 } 767 }
761 SV *k = decode_sv (dec); 769 SV *k = decode_sv (dec);
762 SV *v = decode_sv (dec); 770 SV *v = decode_sv (dec);
763 771
764 hv_store_ent (hv, k, v, 0); 772 hv_store_ent (hv, k, v, 0);
765 SvREFCNT_dec (k); 773 SvREFCNT_dec (k);
774
775fail:
776 ;
766} 777}
767 778
768static SV * 779static SV *
769decode_hv (dec_t *dec) 780decode_hv (dec_t *dec)
770{ 781{
852 && SvCUR (sv) >= minimum_string_length (AvFILLp (dec->stringref) + 1)) 863 && SvCUR (sv) >= minimum_string_length (AvFILLp (dec->stringref) + 1))
853 av_push (dec->stringref, SvREFCNT_inc_NN (sv)); 864 av_push (dec->stringref, SvREFCNT_inc_NN (sv));
854 } 865 }
855 866
856 if (utf8) 867 if (utf8)
868 {
869 if (ecb_expect_false (dec->cbor.flags & F_VALIDATE_UTF8))
870 if (!is_utf8_string (SvPVX (sv), SvCUR (sv)))
871 ERR ("corrupted CBOR data (invalid UTF-8 in text string)");
872
857 SvUTF8_on (sv); 873 SvUTF8_on (sv);
874 }
858 875
859 return sv; 876 return sv;
860 877
861fail: 878fail:
862 SvREFCNT_dec (sv); 879 SvREFCNT_dec (sv);
911 case CBOR_TAG_VALUE_SHAREABLE: 928 case CBOR_TAG_VALUE_SHAREABLE:
912 { 929 {
913 if (ecb_expect_false (!dec->shareable)) 930 if (ecb_expect_false (!dec->shareable))
914 dec->shareable = (AV *)sv_2mortal ((SV *)newAV ()); 931 dec->shareable = (AV *)sv_2mortal ((SV *)newAV ());
915 932
933 if (dec->cbor.flags & F_ALLOW_CYCLES)
934 {
916 sv = newSV (0); 935 sv = newSV (0);
917 av_push (dec->shareable, SvREFCNT_inc_NN (sv)); 936 av_push (dec->shareable, SvREFCNT_inc_NN (sv));
918 937
919 SV *osv = decode_sv (dec); 938 SV *osv = decode_sv (dec);
920 sv_setsv (sv, osv); 939 sv_setsv (sv, osv);
921 SvREFCNT_dec_NN (osv); 940 SvREFCNT_dec_NN (osv);
941 }
942 else
943 {
944 av_push (dec->shareable, &PL_sv_undef);
945 int idx = AvFILLp (dec->shareable);
946 sv = decode_sv (dec);
947 av_store (dec->shareable, idx, SvREFCNT_inc_NN (sv));
948 }
922 } 949 }
923 break; 950 break;
924 951
925 case CBOR_TAG_VALUE_SHAREDREF: 952 case CBOR_TAG_VALUE_SHAREDREF:
926 { 953 {
931 958
932 if (!dec->shareable || (int)idx > AvFILLp (dec->shareable)) 959 if (!dec->shareable || (int)idx > AvFILLp (dec->shareable))
933 ERR ("corrupted CBOR data (sharedref index out of bounds)"); 960 ERR ("corrupted CBOR data (sharedref index out of bounds)");
934 961
935 sv = SvREFCNT_inc_NN (AvARRAY (dec->shareable)[idx]); 962 sv = SvREFCNT_inc_NN (AvARRAY (dec->shareable)[idx]);
963
964 if (sv == &PL_sv_undef)
965 ERR ("cyclic CBOR data structure found, but allow_cycles is not enabled");
936 } 966 }
937 break; 967 break;
938 968
939 case CBOR_TAG_PERL_OBJECT: 969 case CBOR_TAG_PERL_OBJECT:
940 { 970 {
1109 1139
1110 return newSVnv (ecb_binary64_to_double (fp)); 1140 return newSVnv (ecb_binary64_to_double (fp));
1111 } 1141 }
1112 1142
1113 // 0..19 unassigned simple 1143 // 0..19 unassigned simple
1114 // 24 reserved + unassigned (reserved values are not encodable) 1144 // 24 reserved + unassigned simple (reserved values are not encodable)
1145 // 28-30 unassigned misc
1146 // 31 break code
1115 default: 1147 default:
1116 ERR ("corrupted CBOR data (reserved/unassigned major 7 value)"); 1148 ERR ("corrupted CBOR data (reserved/unassigned/unexpected major 7 value)");
1117 } 1149 }
1118 1150
1119 break; 1151 break;
1120 } 1152 }
1121 1153
1148 if (dec.cur != dec.end && !dec.err) 1180 if (dec.cur != dec.end && !dec.err)
1149 dec.err = "garbage after CBOR object"; 1181 dec.err = "garbage after CBOR object";
1150 1182
1151 if (dec.err) 1183 if (dec.err)
1152 { 1184 {
1185 if (dec.shareable)
1186 {
1187 // need to break cyclic links, which whould all be in shareable
1188 int i;
1189 SV **svp;
1190
1191 for (i = av_len (dec.shareable) + 1; i--; )
1192 if ((svp = av_fetch (dec.shareable, i, 0)))
1193 sv_setsv (*svp, &PL_sv_undef);
1194 }
1195
1153 SvREFCNT_dec (sv); 1196 SvREFCNT_dec (sv);
1154 croak ("%s, at offset %d (octet 0x%02x)", dec.err, dec.cur - (U8 *)data, (int)(uint8_t)*dec.cur); 1197 croak ("%s, at offset %d (octet 0x%02x)", dec.err, dec.cur - (U8 *)data, (int)(uint8_t)*dec.cur);
1155 } 1198 }
1156 1199
1157 sv = sv_2mortal (sv); 1200 sv = sv_2mortal (sv);
1158 1201
1159 return sv; 1202 return sv;
1160} 1203}
1161 1204
1205/////////////////////////////////////////////////////////////////////////////
1206// incremental parser
1207
1208#define INCR_DONE(cbor) (AvFILLp (cbor->incr_count) < 0)
1209
1210// returns 0 for notyet, 1 for success or error
1211static int
1212incr_parse (CBOR *self, SV *cborstr)
1213{
1214 STRLEN cur;
1215 SvPV (cborstr, cur);
1216
1217 while (ecb_expect_true (self->incr_need <= cur))
1218 {
1219 // table of integer count bytes
1220 static I8 incr_len[MINOR_MASK + 1] = {
1221 0, 0, 0, 0, 0, 0, 0, 0,
1222 0, 0, 0, 0, 0, 0, 0, 0,
1223 0, 0, 0, 0, 0, 0, 0, 0,
1224 1, 2, 4, 8,-1,-1,-1,-2
1225 };
1226
1227 const U8 *p = SvPVX (cborstr) + self->incr_pos;
1228 U8 m = *p & MINOR_MASK;
1229 IV count = SvIVX (AvARRAY (self->incr_count)[AvFILLp (self->incr_count)]);
1230 I8 ilen = incr_len[m];
1231
1232 self->incr_need = self->incr_pos + 1;
1233
1234 if (ecb_expect_false (ilen < 0))
1235 {
1236 if (m != MINOR_INDEF)
1237 return 1; // error
1238
1239 if (*p == (MAJOR_MISC | MINOR_INDEF))
1240 {
1241 if (count >= 0)
1242 return 1; // error
1243
1244 count = 1;
1245 }
1246 else
1247 {
1248 av_push (self->incr_count, newSViv (-1)); //TODO: nest
1249 count = -1;
1250 }
1251 }
1252 else
1253 {
1254 self->incr_need += ilen;
1255 if (ecb_expect_false (self->incr_need > cur))
1256 return 0;
1257
1258 int major = *p >> MAJOR_SHIFT;
1259
1260 switch (major)
1261 {
1262 case MAJOR_BYTES >> MAJOR_SHIFT:
1263 case MAJOR_TEXT >> MAJOR_SHIFT:
1264 case MAJOR_ARRAY >> MAJOR_SHIFT:
1265 case MAJOR_MAP >> MAJOR_SHIFT:
1266 {
1267 UV len;
1268
1269 if (ecb_expect_false (ilen))
1270 {
1271 len = 0;
1272
1273 do {
1274 len = (len << 8) | *++p;
1275 } while (--ilen);
1276 }
1277 else
1278 len = m;
1279
1280 switch (major)
1281 {
1282 case MAJOR_BYTES >> MAJOR_SHIFT:
1283 case MAJOR_TEXT >> MAJOR_SHIFT:
1284 self->incr_need += len;
1285 if (ecb_expect_false (self->incr_need > cur))
1286 return 0;
1287
1288 break;
1289
1290 case MAJOR_MAP >> MAJOR_SHIFT:
1291 len <<= 1;
1292 case MAJOR_ARRAY >> MAJOR_SHIFT:
1293 if (len)
1294 {
1295 av_push (self->incr_count, newSViv (len + 1)); //TODO: nest
1296 count = len + 1;
1297 }
1298 break;
1299 }
1300 }
1301 }
1302 }
1303
1304 self->incr_pos = self->incr_need;
1305
1306 if (count > 0)
1307 {
1308 while (!--count)
1309 {
1310 if (!AvFILLp (self->incr_count))
1311 return 1; // done
1312
1313 SvREFCNT_dec_NN (av_pop (self->incr_count));
1314 count = SvIVX (AvARRAY (self->incr_count)[AvFILLp (self->incr_count)]);
1315 }
1316
1317 SvIVX (AvARRAY (self->incr_count)[AvFILLp (self->incr_count)]) = count;
1318 }
1319 }
1320
1321 return 0;
1322}
1323
1324
1162///////////////////////////////////////////////////////////////////////////// 1325/////////////////////////////////////////////////////////////////////////////
1163// XS interface functions 1326// XS interface functions
1164 1327
1165MODULE = CBOR::XS PACKAGE = CBOR::XS 1328MODULE = CBOR::XS PACKAGE = CBOR::XS
1166 1329
1206void shrink (CBOR *self, int enable = 1) 1369void shrink (CBOR *self, int enable = 1)
1207 ALIAS: 1370 ALIAS:
1208 shrink = F_SHRINK 1371 shrink = F_SHRINK
1209 allow_unknown = F_ALLOW_UNKNOWN 1372 allow_unknown = F_ALLOW_UNKNOWN
1210 allow_sharing = F_ALLOW_SHARING 1373 allow_sharing = F_ALLOW_SHARING
1374 allow_cycles = F_ALLOW_CYCLES
1211 pack_strings = F_PACK_STRINGS 1375 pack_strings = F_PACK_STRINGS
1376 validate_utf8 = F_VALIDATE_UTF8
1212 PPCODE: 1377 PPCODE:
1213{ 1378{
1214 if (enable) 1379 if (enable)
1215 self->flags |= ix; 1380 self->flags |= ix;
1216 else 1381 else
1222void get_shrink (CBOR *self) 1387void get_shrink (CBOR *self)
1223 ALIAS: 1388 ALIAS:
1224 get_shrink = F_SHRINK 1389 get_shrink = F_SHRINK
1225 get_allow_unknown = F_ALLOW_UNKNOWN 1390 get_allow_unknown = F_ALLOW_UNKNOWN
1226 get_allow_sharing = F_ALLOW_SHARING 1391 get_allow_sharing = F_ALLOW_SHARING
1392 get_allow_cycles = F_ALLOW_CYCLES
1227 get_pack_strings = F_PACK_STRINGS 1393 get_pack_strings = F_PACK_STRINGS
1394 get_validate_utf8 = F_VALIDATE_UTF8
1228 PPCODE: 1395 PPCODE:
1229 XPUSHs (boolSV (self->flags & ix)); 1396 XPUSHs (boolSV (self->flags & ix));
1230 1397
1231void max_depth (CBOR *self, U32 max_depth = 0x80000000UL) 1398void max_depth (CBOR *self, U32 max_depth = 0x80000000UL)
1232 PPCODE: 1399 PPCODE:
1281 EXTEND (SP, 2); 1448 EXTEND (SP, 2);
1282 PUSHs (sv); 1449 PUSHs (sv);
1283 PUSHs (sv_2mortal (newSVuv (offset - SvPVX (cborstr)))); 1450 PUSHs (sv_2mortal (newSVuv (offset - SvPVX (cborstr))));
1284} 1451}
1285 1452
1453void incr_parse (CBOR *self, SV *cborstr)
1454 ALIAS:
1455 incr_parse_multiple = 1
1456 PPCODE:
1457{
1458 if (SvUTF8 (cborstr))
1459 sv_utf8_downgrade (cborstr, 0);
1460
1461 if (!self->incr_count)
1462 {
1463 self->incr_count = newAV ();
1464 self->incr_pos = 0;
1465 self->incr_need = 1;
1466
1467 av_push (self->incr_count, newSViv (1));
1468 }
1469
1470 do
1471 {
1472 if (!incr_parse (self, cborstr))
1473 {
1474 if (self->incr_need > self->max_size && self->max_size)
1475 croak ("attempted decode of CBOR text of %lu bytes size, but max_size is set to %lu",
1476 (unsigned long)self->incr_need, (unsigned long)self->max_size);
1477
1478 break;
1479 }
1480
1481 SV *sv;
1482 char *offset;
1483
1484 PUTBACK; sv = decode_cbor (cborstr, self, &offset); SPAGAIN;
1485 XPUSHs (sv);
1486
1487 sv_chop (cborstr, offset);
1488
1489 av_clear (self->incr_count);
1490 av_push (self->incr_count, newSViv (1));
1491
1492 self->incr_pos = 0;
1493 self->incr_need = self->incr_pos + 1;
1494 }
1495 while (ix);
1496}
1497
1498void incr_reset (CBOR *self)
1499 CODE:
1500{
1501 SvREFCNT_dec (self->incr_count);
1502 self->incr_count = 0;
1503}
1504
1286void DESTROY (CBOR *self) 1505void DESTROY (CBOR *self)
1287 PPCODE: 1506 PPCODE:
1288 cbor_free (self); 1507 cbor_free (self);
1289 1508
1290PROTOTYPES: ENABLE 1509PROTOTYPES: ENABLE
1291 1510
1292void encode_cbor (SV *scalar) 1511void encode_cbor (SV *scalar)
1512 ALIAS:
1513 encode_cbor = 0
1514 encode_cbor_sharing = F_ALLOW_SHARING
1293 PPCODE: 1515 PPCODE:
1294{ 1516{
1295 CBOR cbor; 1517 CBOR cbor;
1296 cbor_init (&cbor); 1518 cbor_init (&cbor);
1519 cbor.flags |= ix;
1297 PUTBACK; scalar = encode_cbor (scalar, &cbor); SPAGAIN; 1520 PUTBACK; scalar = encode_cbor (scalar, &cbor); SPAGAIN;
1298 XPUSHs (scalar); 1521 XPUSHs (scalar);
1299} 1522}
1300 1523
1301void decode_cbor (SV *cborstr) 1524void decode_cbor (SV *cborstr)

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines