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

Comparing Convert-BER-XS/XS.xs (file contents):
Revision 1.2 by root, Fri Apr 19 16:49:02 2019 UTC vs.
Revision 1.3 by root, Fri Apr 19 19:46:29 2019 UTC

10 ASN_INTEGER32 = 0x02, 10 ASN_INTEGER32 = 0x02,
11 ASN_BIT_STRING = 0x03, 11 ASN_BIT_STRING = 0x03,
12 ASN_OCTET_STRING = 0x04, 12 ASN_OCTET_STRING = 0x04,
13 ASN_NULL = 0x05, 13 ASN_NULL = 0x05,
14 ASN_OBJECT_IDENTIFIER = 0x06, 14 ASN_OBJECT_IDENTIFIER = 0x06,
15 ASN_OID = 0x06, //X
16 ASN_OBJECT_DESCRIPTOR = 0x07, //X
17 ASN_EXTERNAL = 0x08, //X
15 ASN_REAL = 0x09, //X 18 ASN_REAL = 0x09, //X
16 ASN_ENUMERATED = 0x0a, //X 19 ASN_ENUMERATED = 0x0a, //X
20 ASN_EMBEDDED_PDV = 0x0b, //X
21 ASN_UTF8_STRING = 0x0c, //X
22 ASN_RELATIVE_OID = 0x0d, //X
17 ASN_SEQUENCE = 0x10, 23 ASN_SEQUENCE = 0x10,
18 ASN_SET = 0x11, //X 24 ASN_SET = 0x11, //X
25 ASN_NUMERIC_STRING = 0x12, //X
26 ASN_PRINTABLE_STRING = 0x13, //X
27 ASN_TELETEX_STRING = 0x14, //X
28 ASN_T61_STRING = 0x14, //X
29 ASN_VIDEOTEX_STRING = 0x15, //X
30 ASN_IA5_STRING = 0x16, //X
31 ASN_ASCII_STRING = 0x16, //X
19 ASN_UTC_TIME = 0x17, //X 32 ASN_UTC_TIME = 0x17, //X
20 ASN_GENERAL_TIME = 0x18, //X 33 ASN_GENERALIZED_TIME = 0x18, //X
34 ASN_GRAPHIC_STRING = 0x19, //X
35 ASN_VISIBLE_STRING = 0x1a, //X
36 ASN_ISO646_STRING = 0x1a, //X
37 ASN_GENERAL_STRING = 0x1b, //X
38 ASN_UNIVERSAL_STRING = 0x1c, //X
39 ASN_CHARACTER_STRING = 0x1d, //X
40 ASN_BMPSTRING = 0x1e, //X
21 41
22 ASN_TAG_BER = 0x1f, 42 ASN_TAG_BER = 0x1f,
23 ASN_TAG_MASK = 0x1f, 43 ASN_TAG_MASK = 0x1f,
24 44
25 // primitive/constructed 45 // primitive/constructed
33 53
34 ASN_CLASS_MASK = 0xc0, 54 ASN_CLASS_MASK = 0xc0,
35 ASN_CLASS_SHIFT = 6, 55 ASN_CLASS_SHIFT = 6,
36 56
37 // ASN_APPLICATION SNMP 57 // ASN_APPLICATION SNMP
38 ASN_IPADDRESS = 0x00, 58 SNMP_IPADDRESS = 0x00,
39 ASN_COUNTER32 = 0x01, 59 SNMP_COUNTER32 = 0x01,
40 ASN_UNSIGNED32 = 0x02, 60 SNMP_UNSIGNED32 = 0x02,
41 ASN_TIMETICKS = 0x03, 61 SNMP_TIMETICKS = 0x03,
42 ASN_OPAQUE = 0x04, 62 SNMP_OPAQUE = 0x04,
43 ASN_COUNTER64 = 0x06, 63 SNMP_COUNTER64 = 0x06,
44}; 64};
45 65
46enum { 66enum {
47 BER_CLASS = 0, 67 BER_CLASS = 0,
48 BER_TAG = 1, 68 BER_TAG = 1,
51 BER_ARRAYSIZE 71 BER_ARRAYSIZE
52}; 72};
53 73
54#define MAX_OID_STRLEN 4096 74#define MAX_OID_STRLEN 4096
55 75
56static U8 *buf, *cur; 76static SV *buf_sv; // encoding buffer
57static STRLEN len, rem; 77static U8 *buf, *cur, *end; // buffer start, current, end
78
79#if __GNUC__ >= 3
80# define expect(expr,value) __builtin_expect ((expr), (value))
81# define INLINE static inline
82#else
83# define expect(expr,value) (expr)
84# define INLINE static
85#endif
86
87#define expect_false(expr) expect ((expr) != 0, 0)
88#define expect_true(expr) expect ((expr) != 0, 1)
58 89
59// for "small" integers, return a readonly sv, otherwise create a new one 90// for "small" integers, return a readonly sv, otherwise create a new one
60static SV *newSVcacheint (int val) 91static SV *newSVcacheint (int val)
61{ 92{
62 static SV *cache[32]; 93 static SV *cache[32];
63 94
64 if (val < 0 || val >= sizeof (cache)) 95 if (expect_false (val < 0 || val >= sizeof (cache)))
65 return newSViv (val); 96 return newSViv (val);
66 97
67 if (!cache [val]) 98 if (expect_false (!cache [val]))
68 { 99 {
69 cache [val] = newSVuv (val); 100 cache [val] = newSVuv (val);
70 SvREADONLY_on (cache [val]); 101 SvREADONLY_on (cache [val]);
71 } 102 }
72 103
73 return SvREFCNT_inc_NN (cache [val]); 104 return SvREFCNT_inc_NN (cache [val]);
74} 105}
75 106
76///////////////////////////////////////////////////////////////////////////// 107/////////////////////////////////////////////////////////////////////////////
108// decoder
77 109
78static void 110static void
79error (const char *errmsg) 111error (const char *errmsg)
80{ 112{
81 croak ("%s at offset 0x%04x", errmsg, cur - buf); 113 croak ("%s at offset 0x%04x", errmsg, cur - buf);
82} 114}
83 115
84static int 116static void
85need (int count) 117want (UV count)
86{ 118{
87 if (count < 0 || (int)rem < count) 119 if (expect_false ((uintptr_t)(end - cur) < count))
88 {
89 error ("unexpected end of message buffer"); 120 error ("unexpected end of message buffer");
90 return 0;
91 }
92
93 return 1;
94} 121}
95 122
96// get_* functions fetch something from the buffer 123// get_* functions fetch something from the buffer
97// decode_* functions use get_* fun ctions to decode ber values 124// decode_* functions use get_* fun ctions to decode ber values
98 125
126// get n octets
99static U8 * 127static U8 *
100get_n (int count, const U8 *errres) 128get_n (UV count)
101{ 129{
102 if (!need (count)) 130 want (count);
103 return (U8 *)errres;
104
105 U8 *res = cur; 131 U8 *res = cur;
106
107 cur += count; 132 cur += count;
108 rem -= count;
109
110 return res; 133 return res;
111} 134}
112 135
136// get single octet
113static U8 137static U8
114get_u8 (void) 138get_u8 (void)
115{ 139{
116 if (rem <= 0) 140 if (cur == end)
117 {
118 error ("unexpected end of message buffer"); 141 error ("unexpected end of message buffer");
119 return 0;
120 }
121 142
122 rem--;
123 return *cur++; 143 return *cur++;
124} 144}
125 145
146// get ber-encoded integer (i.e. pack "w")
126static U32 147static U32
127get_ber (void) 148get_w (void)
128{ 149{
129 U32 res = 0; 150 U32 res = 0;
130 151
131 for (;;) 152 for (;;)
132 { 153 {
177 { 198 {
178 error ("INTEGER32 length equal to zero"); 199 error ("INTEGER32 length equal to zero");
179 return 0; 200 return 0;
180 } 201 }
181 202
182 U8 *data = get_n (length, 0); 203 U8 *data = get_n (length);
183
184 if (!data)
185 return 0;
186 204
187 if (length > 5 || (length > 4 && data [0])) 205 if (length > 5 || (length > 4 && data [0]))
188 { 206 {
189 error ("INTEGER32 length too long"); 207 error ("INTEGER32 length too long");
190 return 0; 208 return 0;
221 { 239 {
222 error ("INTEGER64 length equal to zero"); 240 error ("INTEGER64 length equal to zero");
223 return 0; 241 return 0;
224 } 242 }
225 243
226 U8 *data = get_n (length, 0); 244 U8 *data = get_n (length);
227
228 if (!data)
229 return 0;
230 245
231 if (length > 9 || (length > 8 && data [0])) 246 if (length > 9 || (length > 8 && data [0]))
232 { 247 {
233 error ("INTEGER64 length too long"); 248 error ("INTEGER64 length too long");
234 return 0; 249 return 0;
258 273
259static SV * 274static SV *
260decode_octet_string (void) 275decode_octet_string (void)
261{ 276{
262 U32 length = get_length (); 277 U32 length = get_length ();
263
264 U8 *data = get_n (length, 0); 278 U8 *data = get_n (length);
265 if (!data)
266 {
267 error ("OCTET STRING too long");
268 return &PL_sv_undef;
269 }
270
271 return newSVpvn (data, length); 279 return newSVpvn (data, length);
272} 280}
273 281
274// gelper for decode_object_identifier 282// gelper for decode_object_identifier
275static char * 283static char *
311 error ("OBJECT IDENTIFIER length equal to zero"); 319 error ("OBJECT IDENTIFIER length equal to zero");
312 return &PL_sv_undef; 320 return &PL_sv_undef;
313 } 321 }
314 322
315 U8 *end = cur + length; 323 U8 *end = cur + length;
316 U32 w = get_ber (); 324 U32 w = get_w ();
317 325
318 static char oid[MAX_OID_STRLEN]; // must be static 326 static char oid[MAX_OID_STRLEN]; // must be static
319 char *app = oid; 327 char *app = oid;
320 328
321 app = write_uv (app, (U8)w / 40); 329 app = write_uv (app, (U8)w / 40);
323 app = write_uv (app, (U8)w % 40); 331 app = write_uv (app, (U8)w % 40);
324 332
325 // we assume an oid component is never > 64 bytes 333 // we assume an oid component is never > 64 bytes
326 while (cur < end && oid + sizeof (oid) - app > 64) 334 while (cur < end && oid + sizeof (oid) - app > 64)
327 { 335 {
328 w = get_ber (); 336 w = get_w ();
329 *app++ = '.'; 337 *app++ = '.';
330 app = write_uv (app, w); 338 app = write_uv (app, w);
331 } 339 }
332 340
333 return newSVpvn (oid, app - oid); 341 return newSVpvn (oid, app - oid);
343 int constructed = identifier & ASN_CONSTRUCTED; 351 int constructed = identifier & ASN_CONSTRUCTED;
344 int klass = identifier & ASN_CLASS_MASK; 352 int klass = identifier & ASN_CLASS_MASK;
345 int tag = identifier & ASN_TAG_MASK; 353 int tag = identifier & ASN_TAG_MASK;
346 354
347 if (tag == ASN_TAG_BER) 355 if (tag == ASN_TAG_BER)
348 tag = get_ber (); 356 tag = get_w ();
349 357
350 if (tag == ASN_TAG_BER) 358 if (tag == ASN_TAG_BER)
351 tag = get_ber (); 359 tag = get_w ();
352 360
353 if (constructed) 361 if (constructed)
354 { 362 {
355 U32 len = get_length (); 363 U32 len = get_length ();
356 U32 seqend = (cur - buf) + len; 364 U32 seqend = (cur - buf) + len;
377 385
378 case ASN_INTEGER32: 386 case ASN_INTEGER32:
379 res = decode_integer32 (); 387 res = decode_integer32 ();
380 break; 388 break;
381 389
382 case ASN_APPLICATION | ASN_UNSIGNED32: 390 case ASN_APPLICATION | SNMP_UNSIGNED32:
383 case ASN_APPLICATION | ASN_COUNTER32: 391 case ASN_APPLICATION | SNMP_COUNTER32:
384 case ASN_APPLICATION | ASN_TIMETICKS: 392 case ASN_APPLICATION | SNMP_TIMETICKS:
385 res = decode_unsigned32 (); 393 res = decode_unsigned32 ();
386 break; 394 break;
387 395
388#if 0 // handled by default case 396#if 0 // handled by default case
389 case ASN_OCTET_STRING: 397 case ASN_OCTET_STRING:
391 case ASN_APPLICATION | ASN_OPAQUE: 399 case ASN_APPLICATION | ASN_OPAQUE:
392 res = decode_octet_string (); 400 res = decode_octet_string ();
393 break; 401 break;
394#endif 402#endif
395 403
396 case ASN_APPLICATION | ASN_COUNTER64: 404 case ASN_APPLICATION | SNMP_COUNTER64:
397 res = decode_integer64 (); 405 res = decode_integer64 ();
398 break; 406 break;
399 407
400 default: 408 default:
401 res = decode_octet_string (); 409 res = decode_octet_string ();
409 AvARRAY (av)[BER_CONSTRUCTED] = newSVcacheint (constructed ? 1 : 0); 417 AvARRAY (av)[BER_CONSTRUCTED] = newSVcacheint (constructed ? 1 : 0);
410 AvARRAY (av)[BER_DATA ] = res; 418 AvARRAY (av)[BER_DATA ] = res;
411 419
412 return newRV_noinc ((SV *)av); 420 return newRV_noinc ((SV *)av);
413} 421}
422
423/////////////////////////////////////////////////////////////////////////////
424// encoder
425
426/* adds two STRLENs together, slow, and with paranoia */
427static STRLEN
428strlen_sum (STRLEN l1, STRLEN l2)
429{
430 size_t sum = l1 + l2;
431
432 if (sum < (size_t)l2 || sum != (size_t)(STRLEN)sum)
433 croak ("JSON::XS: string size overflow");
434
435 return sum;
436}
437
438static void
439set_buf (SV *sv)
440{
441 STRLEN len;
442 buf_sv = sv;
443 buf = SvPVbyte (buf_sv, len);
444 cur = buf;
445 end = buf + len;
446}
447
448/* similar to SvGROW, but somewhat safer and guarantees exponential realloc strategy */
449static char *
450my_sv_grow (SV *sv, size_t len1, size_t len2)
451{
452 len1 = strlen_sum (len1, len2);
453 len1 = strlen_sum (len1, len1 >> 1);
454
455 if (len1 > 4096 - 24)
456 len1 = (len1 | 4095) - 24;
457
458 return SvGROW (sv, len1);
459}
460
461static void
462need (STRLEN len)
463{
464 if (expect_false ((uintptr_t)(end - cur) < len))
465 {
466 STRLEN pos = cur - buf;
467 buf = my_sv_grow (buf_sv, pos, len);
468 cur = buf + pos;
469 end = buf + SvLEN (buf_sv) - 1;
470 }
471}
472
473static void
474put_u8 (int val)
475{
476 need (1);
477 *cur++ = val;
478}
479
480static void
481put_w_nocheck (U32 val)
482{
483 *cur = (val >> 7 * 4) | 0x80; cur += val >= (1 << (7 * 4));
484 *cur = (val >> 7 * 3) | 0x80; cur += val >= (1 << (7 * 3));
485 *cur = (val >> 7 * 2) | 0x80; cur += val >= (1 << (7 * 2));
486 *cur = (val >> 7 * 1) | 0x80; cur += val >= (1 << (7 * 1));
487 *cur = val & 0x7f; cur += 1;
488}
489
490static void
491put_w (U32 val)
492{
493 need (5); // we only handle up to 5 bytes
494
495 put_w_nocheck (val);
496}
497
498static U8 *
499put_length_at (U32 val, U8 *cur)
500{
501 if (val < 0x7fU)
502 *cur++ = val;
503 else
504 {
505 U8 *lenb = cur++;
506
507 *cur = val >> 24; cur += *cur > 0;
508 *cur = val >> 16; cur += *cur > 0;
509 *cur = val >> 8; cur += *cur > 0;
510 *cur = val ; cur += 1;
511
512 *lenb = 0x80 + cur - lenb - 1;
513 }
514
515 return cur;
516}
517
518static void
519put_length (U32 val)
520{
521 need (5);
522 cur = put_length_at (val, cur);
523}
524
525// return how many bytes the encoded length requires
526static int length_length (U32 val)
527{
528 return val < 0x7fU
529 ? 1
530 : 2 + (val > 0xffU) + (val > 0xffffU) + (val > 0xffffffU);
531}
532
533static void
534encode_octet_string (SV *sv)
535{
536 STRLEN len;
537 char *ptr = SvPVbyte (sv, len);
538
539 put_length (len);
540 need (len);
541 memcpy (cur, ptr, len);
542 cur += len;
543}
544
545static void
546encode_integer32 (IV iv)
547{
548 need (5);
549
550 U8 *lenb = cur++;
551
552 if (iv < 0)
553 {
554 // get two's complement bit pattern - works even on hypthetical non-2c machines
555 U32 uv = iv;
556
557 *cur = uv >> 24; cur += !!(~uv & 0xff800000U);
558 *cur = uv >> 16; cur += !!(~uv & 0xffff8000U);
559 *cur = uv >> 8; cur += !!(~uv & 0xffffff80U);
560 *cur = uv ; cur += 1;
561 }
562 else
563 {
564 *cur = iv >> 24; cur += *cur > 0;
565 *cur = iv >> 16; cur += *cur > 0;
566 *cur = iv >> 8; cur += *cur > 0;
567 *cur = iv ; cur += 1;
568 }
569
570 *lenb = cur - lenb - 1;
571}
572
573static void
574encode_unsigned64 (U64TYPE uv)
575{
576 need (9);
577
578 U8 *lenb = cur++;
579
580 *cur = uv >> 56; cur += *cur > 0;
581 *cur = uv >> 48; cur += *cur > 0;
582 *cur = uv >> 40; cur += *cur > 0;
583 *cur = uv >> 32; cur += *cur > 0;
584 *cur = uv >> 24; cur += *cur > 0;
585 *cur = uv >> 16; cur += *cur > 0;
586 *cur = uv >> 8; cur += *cur > 0;
587 *cur = uv ; cur += 1;
588
589 *lenb = cur - lenb - 1;
590}
591
592// we don't know the length yet, so we optimistically
593// assume the length will need one octet later. if that
594// turns out to be wrong, we memove as needed.
595// mark the beginning
596static STRLEN
597len_fixup_mark ()
598{
599 return cur++ - buf;
600}
601
602// patch up the length
603static void
604len_fixup (STRLEN mark)
605{
606 STRLEN reallen = (cur - buf) - mark - 1;
607 int lenlen = length_length (reallen);
608
609 if (expect_false (lenlen > 1))
610 {
611 // bad luck, we have to shift the bytes to make room for the length
612 need (5);
613 memmove (buf + mark + lenlen, buf + mark + 1, reallen);
614 cur += lenlen - 1;
615 }
616
617 put_length_at (reallen, buf + mark);
618}
619
620static char *
621read_uv (char *str, UV *uv)
622{
623 UV r = 0;
624
625 while (*str >= '0')
626 r = r * 10 + *str++ - '0';
627
628 *uv = r;
629
630 str += !!*str; // advance over any non-zero byte
631
632 return str;
633}
634
635static void
636encode_object_identifier (SV *oid)
637{
638 STRLEN slen;
639 char *ptr = SvPV (oid, slen); // utf8 vs. bytes does not matter
640
641 // we need at most as many octets as the string form
642 need (slen + 1);
643 STRLEN mark = len_fixup_mark ();
644
645 UV w1, w2;
646
647 ptr = read_uv (ptr, &w1);
648 ptr = read_uv (ptr, &w2);
649
650 put_w_nocheck (w1 * 40 + w2);
651
652 while (*ptr)
653 {
654 ptr = read_uv (ptr, &w1);
655 put_w_nocheck (w1);
656 }
657
658 len_fixup (mark);
659}
660
661static void
662encode_ber (SV *tuple)
663{
664 if (expect_false (!SvROK (tuple) || SvTYPE (SvRV (tuple)) != SVt_PVAV))
665 croak ("BER tuple must be array-reference");
666
667 AV *av = (AV *)SvRV (tuple);
668
669 if (expect_false (SvRMAGICAL (av)))
670 croak ("BER tuple must not be tied");
671
672 if (expect_false (AvFILL (av) != BER_ARRAYSIZE - 1))
673 croak ("BER tuple must contain exactly %d elements, not %d", BER_ARRAYSIZE, AvFILL (av) + 1);
674
675 int klass = SvIV (AvARRAY (av)[BER_CLASS]);
676 int tag = SvIV (AvARRAY (av)[BER_TAG]);
677 int constructed = SvIV (AvARRAY (av)[BER_CONSTRUCTED]) ? ASN_CONSTRUCTED : 0;
678 SV *data = AvARRAY (av)[BER_DATA];
679
680 int identifier = (klass << ASN_CLASS_SHIFT) | constructed;
681
682 if (expect_false (tag >= ASN_TAG_BER))
683 {
684 put_u8 (identifier | ASN_TAG_BER);
685 put_w (tag);
686 }
687 else
688 put_u8 (identifier | tag);
689
690 if (constructed)
691 {
692 // we optimistically assume that only one length byte is needed
693 // and adjust later
694 need (1);
695 STRLEN mark = len_fixup_mark ();
696
697 if (expect_false (!SvROK (data) || SvTYPE (SvRV (data)) != SVt_PVAV))
698 croak ("BER constructed data must be array-reference");
699
700 AV *av = (AV *)SvRV (data);
701 int fill = AvFILL (av);
702
703 if (expect_false (SvRMAGICAL (av)))
704 croak ("BER constructed data must not be tied");
705
706 for (int i = 0; i <= fill; ++i)
707 encode_ber (AvARRAY (av)[i]);
708
709 len_fixup (mark);
710 }
711 else
712 switch (identifier | tag)
713 {
714 case ASN_NULL:
715 put_length (0);
716 break;
717
718 case ASN_OBJECT_IDENTIFIER:
719 encode_object_identifier (data);
720 break;
721
722 case ASN_INTEGER32:
723 encode_integer32 (SvIV (data));
724 break;
725
726 case ASN_APPLICATION | SNMP_UNSIGNED32:
727 case ASN_APPLICATION | SNMP_COUNTER32:
728 case ASN_APPLICATION | SNMP_TIMETICKS:
729 case ASN_APPLICATION | SNMP_COUNTER64:
730 encode_unsigned64 (SvUV (data));
731 break;
732
733 default:
734 encode_octet_string (data);
735 break;
736 }
737
738}
739
740/////////////////////////////////////////////////////////////////////////////
414 741
415MODULE = Convert::BER::XS PACKAGE = Convert::BER::XS 742MODULE = Convert::BER::XS PACKAGE = Convert::BER::XS
416 743
417PROTOTYPES: ENABLE 744PROTOTYPES: ENABLE
418 745
438 { "ASN_CONTEXT", ASN_CONTEXT >> ASN_CLASS_SHIFT }, 765 { "ASN_CONTEXT", ASN_CONTEXT >> ASN_CLASS_SHIFT },
439 { "ASN_PRIVATE", ASN_PRIVATE >> ASN_CLASS_SHIFT }, 766 { "ASN_PRIVATE", ASN_PRIVATE >> ASN_CLASS_SHIFT },
440 { "ASN_CLASS_MASK", ASN_CLASS_MASK }, 767 { "ASN_CLASS_MASK", ASN_CLASS_MASK },
441 { "ASN_CLASS_SHIFT", ASN_CLASS_SHIFT }, 768 { "ASN_CLASS_SHIFT", ASN_CLASS_SHIFT },
442 { "ASN_SEQUENCE", ASN_SEQUENCE }, 769 { "ASN_SEQUENCE", ASN_SEQUENCE },
443 { "ASN_IPADDRESS", ASN_IPADDRESS }, 770 { "SNMP_IPADDRESS", SNMP_IPADDRESS },
444 { "ASN_COUNTER32", ASN_COUNTER32 }, 771 { "SNMP_COUNTER32", SNMP_COUNTER32 },
445 { "ASN_UNSIGNED32", ASN_UNSIGNED32 }, 772 { "SNMP_UNSIGNED32", SNMP_UNSIGNED32 },
446 { "ASN_TIMETICKS", ASN_TIMETICKS }, 773 { "SNMP_TIMETICKS", SNMP_TIMETICKS },
447 { "ASN_OPAQUE", ASN_OPAQUE }, 774 { "SNMP_OPAQUE", SNMP_OPAQUE },
448 { "ASN_COUNTER64", ASN_COUNTER64 }, 775 { "SNMP_COUNTER64", SNMP_COUNTER64 },
449 776
450 { "BER_CLASS" , BER_CLASS }, 777 { "BER_CLASS" , BER_CLASS },
451 { "BER_TAG" , BER_TAG }, 778 { "BER_TAG" , BER_TAG },
452 { "BER_CONSTRUCTED", BER_CONSTRUCTED }, 779 { "BER_CONSTRUCTED", BER_CONSTRUCTED },
453 { "BER_DATA" , BER_DATA }, 780 { "BER_DATA" , BER_DATA },
459 786
460SV * 787SV *
461ber_decode (SV *ber) 788ber_decode (SV *ber)
462 CODE: 789 CODE:
463{ 790{
791 STRLEN len;
792
464 buf = SvPVbyte (ber, len); 793 buf = SvPVbyte (ber, len);
465 cur = buf; 794 cur = buf;
466 rem = len; 795 end = buf + len;
467 796
468 RETVAL = decode_ber (); 797 RETVAL = decode_ber ();
469} 798}
470 OUTPUT: RETVAL 799 OUTPUT: RETVAL
471 800
490 ? &PL_sv_yes : &PL_sv_no); 819 ? &PL_sv_yes : &PL_sv_no);
491} 820}
492 821
493void 822void
494ber_is_seq (SV *tuple) 823ber_is_seq (SV *tuple)
495 PROTOTYPE: $
496 PPCODE: 824 PPCODE:
497{ 825{
498 if (!SvOK (tuple)) 826 if (!SvOK (tuple))
499 XSRETURN_UNDEF; 827 XSRETURN_UNDEF;
500 828
510 ? AvARRAY (av)[BER_DATA] : &PL_sv_undef); 838 ? AvARRAY (av)[BER_DATA] : &PL_sv_undef);
511} 839}
512 840
513void 841void
514ber_is_i32 (SV *tuple, IV value) 842ber_is_i32 (SV *tuple, IV value)
515 PROTOTYPE: $$
516 PPCODE: 843 PPCODE:
517{ 844{
518 if (!SvOK (tuple)) 845 if (!SvOK (tuple))
519 XSRETURN_NO; 846 XSRETURN_NO;
520 847
531 ? &PL_sv_yes : &PL_sv_no); 858 ? &PL_sv_yes : &PL_sv_no);
532} 859}
533 860
534void 861void
535ber_is_oid (SV *tuple, SV *oid) 862ber_is_oid (SV *tuple, SV *oid)
536 PROTOTYPE: $$
537 PPCODE: 863 PPCODE:
538{ 864{
539 if (!SvOK (tuple)) 865 if (!SvOK (tuple))
540 XSRETURN_NO; 866 XSRETURN_NO;
541 867
550 && !SvIV (AvARRAY (av)[BER_CONSTRUCTED]) 876 && !SvIV (AvARRAY (av)[BER_CONSTRUCTED])
551 && sv_eq (AvARRAY (av)[BER_DATA], oid) 877 && sv_eq (AvARRAY (av)[BER_DATA], oid)
552 ? &PL_sv_yes : &PL_sv_no); 878 ? &PL_sv_yes : &PL_sv_no);
553} 879}
554 880
881#############################################################################
882
883void
884ber_encode (SV *tuple)
885 PPCODE:
886{
887 buf_sv = sv_2mortal (NEWSV (0, 256));
888 SvPOK_only (buf_sv);
889 set_buf (buf_sv);
890
891 encode_ber (tuple);
892
893 SvCUR_set (buf_sv, cur - buf);
894 XPUSHs (buf_sv);
895}
896

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines