ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Convert-BER-XS/XS.xs
Revision: 1.4
Committed: Fri Apr 19 20:38:38 2019 UTC (5 years, 1 month ago) by root
Branch: MAIN
CVS Tags: rel-0_2
Changes since 1.3: +62 -31 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.1 #include "EXTERN.h"
2     #include "perl.h"
3     #include "XSUB.h"
4    
5     // C99 required
6    
7     enum {
8     // ASN_TAG
9     ASN_BOOLEAN = 0x01,
10     ASN_INTEGER32 = 0x02,
11     ASN_BIT_STRING = 0x03,
12     ASN_OCTET_STRING = 0x04,
13     ASN_NULL = 0x05,
14     ASN_OBJECT_IDENTIFIER = 0x06,
15 root 1.3 ASN_OID = 0x06, //X
16     ASN_OBJECT_DESCRIPTOR = 0x07, //X
17     ASN_EXTERNAL = 0x08, //X
18 root 1.2 ASN_REAL = 0x09, //X
19     ASN_ENUMERATED = 0x0a, //X
20 root 1.3 ASN_EMBEDDED_PDV = 0x0b, //X
21     ASN_UTF8_STRING = 0x0c, //X
22     ASN_RELATIVE_OID = 0x0d, //X
23 root 1.1 ASN_SEQUENCE = 0x10,
24 root 1.2 ASN_SET = 0x11, //X
25 root 1.3 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
32 root 1.2 ASN_UTC_TIME = 0x17, //X
33 root 1.3 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
41 root 1.1
42     ASN_TAG_BER = 0x1f,
43     ASN_TAG_MASK = 0x1f,
44    
45     // primitive/constructed
46     ASN_CONSTRUCTED = 0x20,
47    
48     // ASN_CLASS
49     ASN_UNIVERSAL = 0x00,
50     ASN_APPLICATION = 0x40,
51     ASN_CONTEXT = 0x80,
52     ASN_PRIVATE = 0xc0,
53    
54     ASN_CLASS_MASK = 0xc0,
55     ASN_CLASS_SHIFT = 6,
56    
57 root 1.2 // ASN_APPLICATION SNMP
58 root 1.3 SNMP_IPADDRESS = 0x00,
59     SNMP_COUNTER32 = 0x01,
60     SNMP_UNSIGNED32 = 0x02,
61     SNMP_TIMETICKS = 0x03,
62     SNMP_OPAQUE = 0x04,
63     SNMP_COUNTER64 = 0x06,
64 root 1.1 };
65    
66     enum {
67     BER_CLASS = 0,
68     BER_TAG = 1,
69     BER_CONSTRUCTED = 2,
70     BER_DATA = 3,
71     BER_ARRAYSIZE
72     };
73    
74     #define MAX_OID_STRLEN 4096
75    
76 root 1.3 static SV *buf_sv; // encoding buffer
77     static 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)
89 root 1.1
90     // for "small" integers, return a readonly sv, otherwise create a new one
91     static SV *newSVcacheint (int val)
92     {
93     static SV *cache[32];
94    
95 root 1.3 if (expect_false (val < 0 || val >= sizeof (cache)))
96 root 1.1 return newSViv (val);
97    
98 root 1.3 if (expect_false (!cache [val]))
99 root 1.1 {
100     cache [val] = newSVuv (val);
101     SvREADONLY_on (cache [val]);
102     }
103    
104     return SvREFCNT_inc_NN (cache [val]);
105     }
106    
107     /////////////////////////////////////////////////////////////////////////////
108 root 1.3 // decoder
109 root 1.1
110     static void
111     error (const char *errmsg)
112     {
113     croak ("%s at offset 0x%04x", errmsg, cur - buf);
114     }
115    
116 root 1.3 static void
117     want (UV count)
118 root 1.1 {
119 root 1.3 if (expect_false ((uintptr_t)(end - cur) < count))
120     error ("unexpected end of message buffer");
121 root 1.1 }
122    
123 root 1.2 // get_* functions fetch something from the buffer
124     // decode_* functions use get_* fun ctions to decode ber values
125    
126 root 1.3 // get n octets
127 root 1.1 static U8 *
128 root 1.3 get_n (UV count)
129 root 1.1 {
130 root 1.3 want (count);
131 root 1.1 U8 *res = cur;
132     cur += count;
133     return res;
134     }
135    
136 root 1.3 // get single octet
137 root 1.1 static U8
138 root 1.2 get_u8 (void)
139 root 1.1 {
140 root 1.3 if (cur == end)
141     error ("unexpected end of message buffer");
142 root 1.1
143     return *cur++;
144     }
145    
146 root 1.3 // get ber-encoded integer (i.e. pack "w")
147 root 1.1 static U32
148 root 1.3 get_w (void)
149 root 1.1 {
150     U32 res = 0;
151    
152     for (;;)
153     {
154 root 1.2 U8 c = get_u8 ();
155 root 1.1 res = (res << 7) | (c & 0x7f);
156    
157     if (!(c & 0x80))
158     return res;
159     }
160     }
161    
162     static U32
163 root 1.2 get_length (void)
164 root 1.1 {
165 root 1.2 U32 res = get_u8 ();
166 root 1.1
167     if (res & 0x80)
168     {
169     int cnt = res & 0x7f;
170     res = 0;
171    
172     switch (cnt)
173     {
174     case 0:
175     error ("indefinite ASN.1 lengths not supported");
176     return 0;
177    
178     default:
179     error ("ASN.1 length too long");
180     return 0;
181    
182 root 1.2 case 4: res = (res << 8) | get_u8 ();
183     case 3: res = (res << 8) | get_u8 ();
184     case 2: res = (res << 8) | get_u8 ();
185     case 1: res = (res << 8) | get_u8 ();
186 root 1.1 }
187     }
188    
189     return res;
190     }
191    
192     static U32
193 root 1.2 get_integer32 (void)
194 root 1.1 {
195 root 1.2 U32 length = get_length ();
196 root 1.1
197     if (length <= 0)
198     {
199     error ("INTEGER32 length equal to zero");
200     return 0;
201     }
202    
203 root 1.3 U8 *data = get_n (length);
204 root 1.1
205     if (length > 5 || (length > 4 && data [0]))
206     {
207     error ("INTEGER32 length too long");
208     return 0;
209     }
210    
211     U32 res = data [0] & 0x80 ? 0xffffffff : 0;
212    
213     while (length--)
214     res = (res << 8) | *data++;
215    
216     return res;
217     }
218    
219     static SV *
220 root 1.2 decode_integer32 (void)
221 root 1.1 {
222 root 1.2 return newSViv ((I32)get_integer32 ());
223 root 1.1 }
224    
225     static SV *
226 root 1.2 decode_unsigned32 (void)
227 root 1.1 {
228 root 1.2 return newSVuv ((U32)get_integer32 ());
229 root 1.1 }
230    
231     #if IVSIZE >= 8
232    
233     static U64TYPE
234 root 1.2 get_integer64 (void)
235 root 1.1 {
236 root 1.2 U32 length = get_length ();
237 root 1.1
238     if (length <= 0)
239     {
240     error ("INTEGER64 length equal to zero");
241     return 0;
242     }
243    
244 root 1.3 U8 *data = get_n (length);
245 root 1.1
246     if (length > 9 || (length > 8 && data [0]))
247     {
248     error ("INTEGER64 length too long");
249     return 0;
250     }
251    
252     U64TYPE res = data [0] & 0x80 ? 0xffffffffffffffff : 0;
253    
254     while (length--)
255     res = (res << 8) | *data++;
256    
257     return res;
258     }
259    
260     static SV *
261 root 1.2 decode_integer64 (void)
262 root 1.1 {
263 root 1.2 return newSViv ((I64TYPE)get_integer64 ());
264 root 1.1 }
265    
266     static SV *
267 root 1.2 decode_unsigned64 (void)
268 root 1.1 {
269 root 1.2 return newSVuv ((U64TYPE)get_integer64 ());
270 root 1.1 }
271    
272     #endif
273    
274     static SV *
275 root 1.2 decode_octet_string (void)
276 root 1.1 {
277 root 1.2 U32 length = get_length ();
278 root 1.3 U8 *data = get_n (length);
279 root 1.1 return newSVpvn (data, length);
280     }
281    
282 root 1.2 // gelper for decode_object_identifier
283 root 1.1 static char *
284     write_uv (char *buf, U32 u)
285     {
286     // the one-digit case is absolutely predominant, so this pays off (hopefully)
287     if (u < 10)
288     *buf++ = u + '0';
289     else
290     {
291     char *beg = buf;
292    
293     do
294     {
295     *buf++ = u % 10 + '0';
296     u /= 10;
297     }
298     while (u);
299    
300     // reverse digits
301     for (char *ptr = buf; --ptr != beg; ++beg)
302     {
303     char c = *ptr;
304     *ptr = *beg;
305     *beg = c;
306     }
307     }
308    
309     return buf;
310     }
311    
312     static SV *
313 root 1.2 decode_object_identifier (void)
314 root 1.1 {
315 root 1.2 U32 length = get_length ();
316 root 1.1
317     if (length <= 0)
318     {
319     error ("OBJECT IDENTIFIER length equal to zero");
320     return &PL_sv_undef;
321     }
322    
323     U8 *end = cur + length;
324 root 1.3 U32 w = get_w ();
325 root 1.1
326     static char oid[MAX_OID_STRLEN]; // must be static
327     char *app = oid;
328    
329     app = write_uv (app, (U8)w / 40);
330     *app++ = '.';
331     app = write_uv (app, (U8)w % 40);
332    
333     // we assume an oid component is never > 64 bytes
334     while (cur < end && oid + sizeof (oid) - app > 64)
335     {
336 root 1.3 w = get_w ();
337 root 1.1 *app++ = '.';
338     app = write_uv (app, w);
339     }
340    
341     return newSVpvn (oid, app - oid);
342     }
343    
344     static SV *
345 root 1.2 decode_ber ()
346 root 1.1 {
347 root 1.2 int identifier = get_u8 ();
348 root 1.1
349     SV *res;
350    
351     int constructed = identifier & ASN_CONSTRUCTED;
352     int klass = identifier & ASN_CLASS_MASK;
353     int tag = identifier & ASN_TAG_MASK;
354    
355     if (tag == ASN_TAG_BER)
356 root 1.3 tag = get_w ();
357 root 1.1
358     if (tag == ASN_TAG_BER)
359 root 1.3 tag = get_w ();
360 root 1.1
361     if (constructed)
362     {
363 root 1.2 U32 len = get_length ();
364 root 1.1 U32 seqend = (cur - buf) + len;
365     AV *av = (AV *)sv_2mortal ((SV *)newAV ());
366    
367     while (cur < buf + seqend)
368 root 1.2 av_push (av, decode_ber ());
369 root 1.1
370     if (cur > buf + seqend)
371     croak ("constructed type %02x overflow (%x %x)\n", identifier, cur - buf, seqend);
372    
373     res = newRV_inc ((SV *)av);
374     }
375     else
376     switch (identifier)
377     {
378     case ASN_NULL:
379     res = &PL_sv_undef;
380     break;
381    
382     case ASN_OBJECT_IDENTIFIER:
383 root 1.2 res = decode_object_identifier ();
384 root 1.1 break;
385    
386     case ASN_INTEGER32:
387 root 1.2 res = decode_integer32 ();
388 root 1.1 break;
389    
390 root 1.3 case ASN_APPLICATION | SNMP_UNSIGNED32:
391     case ASN_APPLICATION | SNMP_COUNTER32:
392     case ASN_APPLICATION | SNMP_TIMETICKS:
393 root 1.2 res = decode_unsigned32 ();
394 root 1.1 break;
395    
396     #if 0 // handled by default case
397     case ASN_OCTET_STRING:
398     case ASN_APPLICATION | ASN_IPADDRESS:
399     case ASN_APPLICATION | ASN_OPAQUE:
400 root 1.2 res = decode_octet_string ();
401 root 1.1 break;
402     #endif
403    
404 root 1.3 case ASN_APPLICATION | SNMP_COUNTER64:
405 root 1.2 res = decode_integer64 ();
406 root 1.1 break;
407    
408     default:
409 root 1.2 res = decode_octet_string ();
410 root 1.1 break;
411     }
412    
413     AV *av = newAV ();
414     av_fill (av, BER_ARRAYSIZE - 1);
415     AvARRAY (av)[BER_CLASS ] = newSVcacheint (klass >> ASN_CLASS_SHIFT);
416     AvARRAY (av)[BER_TAG ] = newSVcacheint (tag);
417     AvARRAY (av)[BER_CONSTRUCTED] = newSVcacheint (constructed ? 1 : 0);
418     AvARRAY (av)[BER_DATA ] = res;
419    
420     return newRV_noinc ((SV *)av);
421     }
422    
423 root 1.3 /////////////////////////////////////////////////////////////////////////////
424     // encoder
425    
426     /* adds two STRLENs together, slow, and with paranoia */
427     static STRLEN
428     strlen_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    
438     static void
439     set_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 */
449     static char *
450     my_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    
461     static void
462     need (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    
473     static void
474     put_u8 (int val)
475     {
476     need (1);
477     *cur++ = val;
478     }
479    
480     static void
481     put_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    
490     static void
491     put_w (U32 val)
492     {
493     need (5); // we only handle up to 5 bytes
494    
495     put_w_nocheck (val);
496     }
497    
498     static U8 *
499     put_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    
518     static void
519     put_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
526     static int length_length (U32 val)
527     {
528     return val < 0x7fU
529     ? 1
530     : 2 + (val > 0xffU) + (val > 0xffffU) + (val > 0xffffffU);
531     }
532    
533     static void
534     encode_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    
545     static void
546     encode_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    
573     static void
574     encode_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
596     static STRLEN
597     len_fixup_mark ()
598     {
599     return cur++ - buf;
600     }
601    
602     // patch up the length
603     static void
604     len_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    
620     static char *
621     read_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    
635     static void
636     encode_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    
661 root 1.4 // checkl whether an SV is a BER tuple and returns its AV *
662     static AV *
663     ber_tuple (SV *tuple)
664 root 1.3 {
665 root 1.4 SV *rv;
666    
667     if (expect_false (!SvROK (tuple) || SvTYPE ((rv = SvRV (tuple))) != SVt_PVAV))
668 root 1.3 croak ("BER tuple must be array-reference");
669    
670 root 1.4 if (expect_false (SvRMAGICAL (rv)))
671     croak ("BER tuple must not be tied");
672 root 1.3
673 root 1.4 if (expect_false (AvFILL ((AV *)rv) != BER_ARRAYSIZE - 1))
674     croak ("BER tuple must contain exactly %d elements, not %d", BER_ARRAYSIZE, AvFILL ((AV *)rv) + 1);
675 root 1.3
676 root 1.4 return (AV *)rv;
677     }
678    
679     static void
680     encode_ber (SV *tuple)
681     {
682     AV *av = ber_tuple (tuple);
683 root 1.3
684     int klass = SvIV (AvARRAY (av)[BER_CLASS]);
685     int tag = SvIV (AvARRAY (av)[BER_TAG]);
686     int constructed = SvIV (AvARRAY (av)[BER_CONSTRUCTED]) ? ASN_CONSTRUCTED : 0;
687     SV *data = AvARRAY (av)[BER_DATA];
688    
689     int identifier = (klass << ASN_CLASS_SHIFT) | constructed;
690    
691     if (expect_false (tag >= ASN_TAG_BER))
692     {
693     put_u8 (identifier | ASN_TAG_BER);
694     put_w (tag);
695     }
696     else
697     put_u8 (identifier | tag);
698    
699     if (constructed)
700     {
701     // we optimistically assume that only one length byte is needed
702     // and adjust later
703     need (1);
704     STRLEN mark = len_fixup_mark ();
705    
706     if (expect_false (!SvROK (data) || SvTYPE (SvRV (data)) != SVt_PVAV))
707     croak ("BER constructed data must be array-reference");
708    
709     AV *av = (AV *)SvRV (data);
710     int fill = AvFILL (av);
711    
712     if (expect_false (SvRMAGICAL (av)))
713     croak ("BER constructed data must not be tied");
714    
715     for (int i = 0; i <= fill; ++i)
716     encode_ber (AvARRAY (av)[i]);
717    
718     len_fixup (mark);
719     }
720     else
721     switch (identifier | tag)
722     {
723     case ASN_NULL:
724     put_length (0);
725     break;
726    
727     case ASN_OBJECT_IDENTIFIER:
728     encode_object_identifier (data);
729     break;
730    
731     case ASN_INTEGER32:
732     encode_integer32 (SvIV (data));
733     break;
734    
735     case ASN_APPLICATION | SNMP_UNSIGNED32:
736     case ASN_APPLICATION | SNMP_COUNTER32:
737     case ASN_APPLICATION | SNMP_TIMETICKS:
738     case ASN_APPLICATION | SNMP_COUNTER64:
739     encode_unsigned64 (SvUV (data));
740     break;
741    
742     default:
743     encode_octet_string (data);
744     break;
745     }
746    
747     }
748    
749     /////////////////////////////////////////////////////////////////////////////
750    
751 root 1.1 MODULE = Convert::BER::XS PACKAGE = Convert::BER::XS
752    
753     PROTOTYPES: ENABLE
754    
755     BOOT:
756     {
757     HV *stash = gv_stashpv ("Convert::BER::XS", 1);
758    
759     static const struct {
760     const char *name;
761     IV iv;
762     } *civ, const_iv[] = {
763     { "ASN_BOOLEAN", ASN_BOOLEAN },
764     { "ASN_INTEGER32", ASN_INTEGER32 },
765     { "ASN_BIT_STRING", ASN_BIT_STRING },
766     { "ASN_OCTET_STRING", ASN_OCTET_STRING },
767     { "ASN_NULL", ASN_NULL },
768     { "ASN_OBJECT_IDENTIFIER", ASN_OBJECT_IDENTIFIER },
769     { "ASN_TAG_BER", ASN_TAG_BER },
770     { "ASN_TAG_MASK", ASN_TAG_MASK },
771     { "ASN_CONSTRUCTED", ASN_CONSTRUCTED },
772     { "ASN_UNIVERSAL", ASN_UNIVERSAL >> ASN_CLASS_SHIFT },
773     { "ASN_APPLICATION", ASN_APPLICATION >> ASN_CLASS_SHIFT },
774     { "ASN_CONTEXT", ASN_CONTEXT >> ASN_CLASS_SHIFT },
775     { "ASN_PRIVATE", ASN_PRIVATE >> ASN_CLASS_SHIFT },
776     { "ASN_CLASS_MASK", ASN_CLASS_MASK },
777     { "ASN_CLASS_SHIFT", ASN_CLASS_SHIFT },
778     { "ASN_SEQUENCE", ASN_SEQUENCE },
779 root 1.3 { "SNMP_IPADDRESS", SNMP_IPADDRESS },
780     { "SNMP_COUNTER32", SNMP_COUNTER32 },
781     { "SNMP_UNSIGNED32", SNMP_UNSIGNED32 },
782     { "SNMP_TIMETICKS", SNMP_TIMETICKS },
783     { "SNMP_OPAQUE", SNMP_OPAQUE },
784     { "SNMP_COUNTER64", SNMP_COUNTER64 },
785 root 1.1
786     { "BER_CLASS" , BER_CLASS },
787     { "BER_TAG" , BER_TAG },
788     { "BER_CONSTRUCTED", BER_CONSTRUCTED },
789     { "BER_DATA" , BER_DATA },
790     };
791    
792     for (civ = const_iv + sizeof (const_iv) / sizeof (const_iv [0]); civ > const_iv; civ--)
793     newCONSTSUB (stash, (char *)civ[-1].name, newSViv (civ[-1].iv));
794     }
795    
796     SV *
797     ber_decode (SV *ber)
798     CODE:
799     {
800 root 1.3 STRLEN len;
801    
802 root 1.1 buf = SvPVbyte (ber, len);
803     cur = buf;
804 root 1.3 end = buf + len;
805 root 1.1
806 root 1.2 RETVAL = decode_ber ();
807 root 1.1 }
808     OUTPUT: RETVAL
809    
810     void
811     ber_is (SV *tuple, SV *klass = &PL_sv_undef, SV *tag = &PL_sv_undef, SV *constructed = &PL_sv_undef, SV *data = &PL_sv_undef)
812     PPCODE:
813     {
814     if (!SvOK (tuple))
815     XSRETURN_NO;
816    
817     if (!SvROK (tuple) || SvTYPE (SvRV (tuple)) != SVt_PVAV)
818 root 1.4 croak ("ber_is: tuple must be BER tuple (array-ref)");
819 root 1.1
820     AV *av = (AV *)SvRV (tuple);
821    
822     XPUSHs (
823     (!SvOK (klass) || SvIV (AvARRAY (av)[BER_CLASS ]) == SvIV (klass))
824     && (!SvOK (tag) || SvIV (AvARRAY (av)[BER_TAG ]) == SvIV (tag))
825     && (!SvOK (constructed) || !SvIV (AvARRAY (av)[BER_CONSTRUCTED]) == !SvIV (constructed))
826     && (!SvOK (data) || sv_eq (AvARRAY (av)[BER_DATA ], data))
827 root 1.4 ? &PL_sv_yes : &PL_sv_undef);
828 root 1.1 }
829    
830     void
831     ber_is_seq (SV *tuple)
832     PPCODE:
833     {
834     if (!SvOK (tuple))
835     XSRETURN_UNDEF;
836    
837 root 1.4 AV *av = ber_tuple (tuple);
838 root 1.1
839     XPUSHs (
840     SvIV (AvARRAY (av)[BER_CLASS ]) == ASN_UNIVERSAL
841     && SvIV (AvARRAY (av)[BER_TAG ]) == ASN_SEQUENCE
842     && SvIV (AvARRAY (av)[BER_CONSTRUCTED])
843     ? AvARRAY (av)[BER_DATA] : &PL_sv_undef);
844     }
845    
846     void
847 root 1.4 ber_is_i32 (SV *tuple, SV *value = &PL_sv_undef)
848 root 1.1 PPCODE:
849     {
850     if (!SvOK (tuple))
851     XSRETURN_NO;
852    
853 root 1.4 AV *av = ber_tuple (tuple);
854 root 1.1
855 root 1.4 IV data = SvIV (AvARRAY (av)[BER_DATA]);
856 root 1.1
857     XPUSHs (
858 root 1.4 SvIV (AvARRAY (av)[BER_CLASS ]) == ASN_UNIVERSAL
859     && SvIV (AvARRAY (av)[BER_TAG ]) == ASN_INTEGER32
860     && !SvIV (AvARRAY (av)[BER_CONSTRUCTED])
861     && (!SvOK (value) || data == SvIV (value))
862     ? sv_2mortal (data ? newSViv (data) : newSVpv ("0 but true", 0))
863     : &PL_sv_undef);
864 root 1.1 }
865    
866     void
867 root 1.4 ber_is_oid (SV *tuple, SV *oid = &PL_sv_undef)
868 root 1.1 PPCODE:
869     {
870     if (!SvOK (tuple))
871     XSRETURN_NO;
872    
873 root 1.4 AV *av = ber_tuple (tuple);
874 root 1.1
875     XPUSHs (
876     SvIV (AvARRAY (av)[BER_CLASS ]) == ASN_UNIVERSAL
877     && SvIV (AvARRAY (av)[BER_TAG ]) == ASN_OBJECT_IDENTIFIER
878     && !SvIV (AvARRAY (av)[BER_CONSTRUCTED])
879 root 1.4 && (!SvOK (oid) || sv_eq (AvARRAY (av)[BER_DATA], oid))
880     ? newSVsv (AvARRAY (av)[BER_DATA]) : &PL_sv_undef);
881 root 1.1 }
882    
883 root 1.3 #############################################################################
884    
885     void
886     ber_encode (SV *tuple)
887     PPCODE:
888     {
889     buf_sv = sv_2mortal (NEWSV (0, 256));
890     SvPOK_only (buf_sv);
891     set_buf (buf_sv);
892    
893     encode_ber (tuple);
894    
895     SvCUR_set (buf_sv, cur - buf);
896     XPUSHs (buf_sv);
897     }
898    
899 root 1.4 SV *
900     ber_i32 (IV iv)
901     CODE:
902     {
903     AV *av = newAV ();
904     av_fill (av, BER_ARRAYSIZE - 1);
905     AvARRAY (av)[BER_CLASS ] = newSVcacheint (ASN_UNIVERSAL);
906     AvARRAY (av)[BER_TAG ] = newSVcacheint (ASN_INTEGER32);
907     AvARRAY (av)[BER_CONSTRUCTED] = newSVcacheint (0);
908     AvARRAY (av)[BER_DATA ] = newSViv (iv);
909     RETVAL = newRV_noinc ((SV *)av);
910     }
911     OUTPUT: RETVAL
912    
913     # TODO: not arrayref, but elements?
914     SV *
915     ber_seq (SV *arrayref)
916     CODE:
917     {
918     AV *av = newAV ();
919     av_fill (av, BER_ARRAYSIZE - 1);
920     AvARRAY (av)[BER_CLASS ] = newSVcacheint (ASN_UNIVERSAL);
921     AvARRAY (av)[BER_TAG ] = newSVcacheint (ASN_SEQUENCE);
922     AvARRAY (av)[BER_CONSTRUCTED] = newSVcacheint (1);
923     AvARRAY (av)[BER_DATA ] = newSVsv (arrayref);
924     RETVAL = newRV_noinc ((SV *)av);
925     }
926     OUTPUT: RETVAL
927