ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Convert-BER-XS/XS.xs
Revision: 1.33
Committed: Thu Apr 25 22:30:21 2019 UTC (5 years ago) by root
Branch: MAIN
CVS Tags: rel-1_2
Changes since 1.32: +176 -18 lines
Log Message:
1.2

File Contents

# User Rev Content
1 root 1.1 #include "EXTERN.h"
2     #include "perl.h"
3     #include "XSUB.h"
4    
5 root 1.33 #include <math.h>
6    
7 root 1.12 // C99 required!
8     // this is not just for comments, but also for
9     // integer constant semantics,
10     // sscanf format modifiers and more.
11 root 1.1
12     enum {
13     // ASN_TAG
14     ASN_BOOLEAN = 0x01,
15 root 1.15 ASN_INTEGER = 0x02,
16 root 1.1 ASN_BIT_STRING = 0x03,
17     ASN_OCTET_STRING = 0x04,
18     ASN_NULL = 0x05,
19     ASN_OBJECT_IDENTIFIER = 0x06,
20 root 1.8 ASN_OID = 0x06,
21     ASN_OBJECT_DESCRIPTOR = 0x07,
22     ASN_EXTERNAL = 0x08,
23     ASN_REAL = 0x09,
24     ASN_ENUMERATED = 0x0a,
25     ASN_EMBEDDED_PDV = 0x0b,
26     ASN_UTF8_STRING = 0x0c,
27     ASN_RELATIVE_OID = 0x0d,
28 root 1.1 ASN_SEQUENCE = 0x10,
29 root 1.8 ASN_SET = 0x11,
30     ASN_NUMERIC_STRING = 0x12,
31     ASN_PRINTABLE_STRING = 0x13,
32     ASN_TELETEX_STRING = 0x14,
33     ASN_T61_STRING = 0x14,
34     ASN_VIDEOTEX_STRING = 0x15,
35     ASN_IA5_STRING = 0x16,
36     ASN_ASCII_STRING = 0x16,
37     ASN_UTC_TIME = 0x17,
38     ASN_GENERALIZED_TIME = 0x18,
39     ASN_GRAPHIC_STRING = 0x19,
40     ASN_VISIBLE_STRING = 0x1a,
41     ASN_ISO646_STRING = 0x1a,
42     ASN_GENERAL_STRING = 0x1b,
43     ASN_UNIVERSAL_STRING = 0x1c,
44     ASN_CHARACTER_STRING = 0x1d,
45     ASN_BMP_STRING = 0x1e,
46 root 1.1
47     ASN_TAG_BER = 0x1f,
48     ASN_TAG_MASK = 0x1f,
49    
50     // primitive/constructed
51     ASN_CONSTRUCTED = 0x20,
52    
53     // ASN_CLASS
54     ASN_UNIVERSAL = 0x00,
55 root 1.5 ASN_APPLICATION = 0x01,
56     ASN_CONTEXT = 0x02,
57     ASN_PRIVATE = 0x03,
58 root 1.1
59     ASN_CLASS_MASK = 0xc0,
60     ASN_CLASS_SHIFT = 6,
61    
62 root 1.2 // ASN_APPLICATION SNMP
63 root 1.3 SNMP_IPADDRESS = 0x00,
64     SNMP_COUNTER32 = 0x01,
65 root 1.21 SNMP_GAUGE32 = 0x02,
66 root 1.3 SNMP_UNSIGNED32 = 0x02,
67     SNMP_TIMETICKS = 0x03,
68     SNMP_OPAQUE = 0x04,
69     SNMP_COUNTER64 = 0x06,
70 root 1.1 };
71    
72 root 1.30 // tlow-level types this module can ecode the above (and more) into
73 root 1.1 enum {
74 root 1.5 BER_TYPE_BYTES,
75     BER_TYPE_UTF8,
76     BER_TYPE_UCS2,
77     BER_TYPE_UCS4,
78     BER_TYPE_INT,
79     BER_TYPE_OID,
80     BER_TYPE_RELOID,
81     BER_TYPE_NULL,
82     BER_TYPE_BOOL,
83     BER_TYPE_REAL,
84 root 1.6 BER_TYPE_IPADDRESS,
85 root 1.5 BER_TYPE_CROAK,
86     };
87    
88 root 1.30 // tuple array indices
89 root 1.5 enum {
90 root 1.16 BER_CLASS = 0,
91     BER_TAG = 1,
92     BER_FLAGS = 2,
93     BER_DATA = 3,
94 root 1.1 BER_ARRAYSIZE
95     };
96    
97     #define MAX_OID_STRLEN 4096
98    
99 root 1.5 typedef void profile_type;
100    
101     static profile_type *cur_profile, *default_profile;
102 root 1.3 static SV *buf_sv; // encoding buffer
103     static U8 *buf, *cur, *end; // buffer start, current, end
104    
105 root 1.9 #if PERL_VERSION < 18
106     # define utf8_to_uvchr_buf(s,e,l) utf8_to_uvchr (s, l)
107     #endif
108    
109 root 1.33 #ifndef SvREFCNT_inc_NN
110     #define SvREFCNT_inc_NN(x) SvREFCNT_inc (x)
111     #endif
112     #ifndef SvREFCNT_dec_NN
113     #define SvREFCNT_dec_NN(x) SvREFCNT_dec (x)
114     #endif
115    
116 root 1.3 #if __GNUC__ >= 3
117     # define expect(expr,value) __builtin_expect ((expr), (value))
118     # define INLINE static inline
119     #else
120     # define expect(expr,value) (expr)
121     # define INLINE static
122     #endif
123    
124     #define expect_false(expr) expect ((expr) != 0, 0)
125     #define expect_true(expr) expect ((expr) != 0, 1)
126 root 1.1
127 root 1.5 /////////////////////////////////////////////////////////////////////////////
128    
129     static SV *sviv_cache[32];
130    
131 root 1.1 // for "small" integers, return a readonly sv, otherwise create a new one
132     static SV *newSVcacheint (int val)
133     {
134 root 1.5 if (expect_false (val < 0 || val >= sizeof (sviv_cache)))
135 root 1.1 return newSViv (val);
136    
137 root 1.5 if (expect_false (!sviv_cache [val]))
138 root 1.1 {
139 root 1.5 sviv_cache [val] = newSVuv (val);
140     SvREADONLY_on (sviv_cache [val]);
141 root 1.1 }
142    
143 root 1.5 return SvREFCNT_inc_NN (sviv_cache [val]);
144     }
145    
146     /////////////////////////////////////////////////////////////////////////////
147    
148     static HV *profile_stash;
149    
150     static profile_type *
151     SvPROFILE (SV *profile)
152     {
153     if (!SvOK (profile))
154 root 1.6 return default_profile;
155 root 1.5
156     if (!SvROK (profile))
157 root 1.26 croak ("Convert::BER::XS::Profile expected");
158 root 1.5
159     profile = SvRV (profile);
160    
161     if (SvSTASH (profile) != profile_stash)
162 root 1.26 croak ("Convert::BER::XS::Profile expected");
163 root 1.5
164     return (void *)profile;
165     }
166    
167     static int
168     profile_lookup (profile_type *profile, int klass, int tag)
169     {
170     SV *sv = (SV *)profile;
171     U32 idx = (tag << 2) + klass;
172    
173     if (expect_false (idx >= SvCUR (sv)))
174     return BER_TYPE_BYTES;
175    
176     return SvPVX (sv)[idx];
177     }
178    
179 root 1.10 static void
180 root 1.5 profile_set (profile_type *profile, int klass, int tag, int type)
181     {
182     SV *sv = (SV *)profile;
183     U32 idx = (tag << 2) + klass;
184     STRLEN oldlen = SvCUR (sv);
185     STRLEN newlen = idx + 2;
186    
187     if (idx >= oldlen)
188     {
189     sv_grow (sv, newlen);
190     memset (SvPVX (sv) + oldlen, BER_TYPE_BYTES, newlen - oldlen);
191     SvCUR_set (sv, newlen);
192     }
193    
194     SvPVX (sv)[idx] = type;
195     }
196    
197     static SV *
198 root 1.14 profile_new (void)
199 root 1.5 {
200     SV *sv = newSVpvn ("", 0);
201    
202     static const struct {
203     int klass;
204     int tag;
205     int type;
206     } *celem, default_map[] = {
207     { ASN_UNIVERSAL, ASN_BOOLEAN , BER_TYPE_BOOL },
208 root 1.15 { ASN_UNIVERSAL, ASN_INTEGER , BER_TYPE_INT },
209 root 1.5 { ASN_UNIVERSAL, ASN_NULL , BER_TYPE_NULL },
210     { ASN_UNIVERSAL, ASN_OBJECT_IDENTIFIER, BER_TYPE_OID },
211     { ASN_UNIVERSAL, ASN_RELATIVE_OID , BER_TYPE_RELOID },
212     { ASN_UNIVERSAL, ASN_REAL , BER_TYPE_REAL },
213 root 1.13 { ASN_UNIVERSAL, ASN_ENUMERATED , BER_TYPE_INT },
214 root 1.5 { ASN_UNIVERSAL, ASN_UTF8_STRING , BER_TYPE_UTF8 },
215     { ASN_UNIVERSAL, ASN_BMP_STRING , BER_TYPE_UCS2 },
216     { ASN_UNIVERSAL, ASN_UNIVERSAL_STRING , BER_TYPE_UCS4 },
217     };
218    
219 root 1.11 for (celem = default_map + sizeof (default_map) / sizeof (default_map [0]); celem-- > default_map; )
220     profile_set ((profile_type *)sv, celem->klass, celem->tag, celem->type);
221 root 1.5
222     return sv_bless (newRV_noinc (sv), profile_stash);
223 root 1.1 }
224    
225     /////////////////////////////////////////////////////////////////////////////
226 root 1.3 // decoder
227 root 1.1
228     static void
229     error (const char *errmsg)
230     {
231     croak ("%s at offset 0x%04x", errmsg, cur - buf);
232     }
233    
234 root 1.3 static void
235     want (UV count)
236 root 1.1 {
237 root 1.3 if (expect_false ((uintptr_t)(end - cur) < count))
238     error ("unexpected end of message buffer");
239 root 1.1 }
240    
241 root 1.2 // get_* functions fetch something from the buffer
242     // decode_* functions use get_* fun ctions to decode ber values
243    
244 root 1.25 // get single octet
245     static U8
246     get_u8 (void)
247     {
248     if (cur == end)
249     error ("unexpected end of message buffer");
250    
251     return *cur++;
252     }
253    
254 root 1.3 // get n octets
255 root 1.1 static U8 *
256 root 1.3 get_n (UV count)
257 root 1.1 {
258 root 1.3 want (count);
259 root 1.1 U8 *res = cur;
260     cur += count;
261     return res;
262     }
263    
264 root 1.3 // get ber-encoded integer (i.e. pack "w")
265 root 1.15 static UV
266 root 1.3 get_w (void)
267 root 1.1 {
268 root 1.15 UV res = 0;
269 root 1.20 U8 c = get_u8 ();
270    
271     if (expect_false (c == 0x80))
272 root 1.33 error ("invalid BER padding (X.690 8.1.2.4.2, 8.19.2)");
273 root 1.1
274     for (;;)
275     {
276 root 1.23 if (expect_false (res >> UVSIZE * 8 - 7))
277 root 1.25 error ("BER variable length integer overflow");
278 root 1.23
279 root 1.1 res = (res << 7) | (c & 0x7f);
280    
281 root 1.29 if (expect_true (!(c & 0x80)))
282 root 1.1 return res;
283 root 1.20
284     c = get_u8 ();
285 root 1.1 }
286     }
287    
288 root 1.15 static UV
289 root 1.2 get_length (void)
290 root 1.1 {
291 root 1.15 UV res = get_u8 ();
292 root 1.1
293 root 1.29 if (expect_false (res & 0x80))
294 root 1.1 {
295 root 1.29 U8 cnt = res & 0x7f;
296    
297     // this genewrates quite ugly code, but the overhead
298     // of copying the bytes for these lengths is probably so high
299     // that a slightly inefficient get_length won't matter.
300 root 1.1
301 root 1.29 if (expect_false (cnt == 0))
302 root 1.33 error ("invalid use of indefinite BER length form in primitive encoding (X.690 8.1.3.2)");
303 root 1.1
304 root 1.29 if (expect_false (cnt > UVSIZE))
305     error ("BER value length too long (must fit into UV) or BER reserved value in length (X.690 8.1.3.5)");
306 root 1.18
307 root 1.29 want (cnt);
308 root 1.1
309 root 1.29 res = 0;
310     do
311     res = (res << 8) | *cur++;
312     while (--cnt);
313 root 1.1 }
314    
315     return res;
316     }
317    
318     static SV *
319 root 1.30 decode_int (UV len)
320 root 1.1 {
321 root 1.15 if (!len)
322 root 1.25 error ("invalid BER_TYPE_INT length zero (X.690 8.3.1)");
323 root 1.20
324     U8 *data = get_n (len);
325    
326     if (expect_false (len > 1))
327 root 1.1 {
328 root 1.20 U16 mask = (data [0] << 8) | data [1] & 0xff80;
329    
330     if (expect_false (mask == 0xff80 || mask == 0x0000))
331 root 1.33 error ("invalid padding in BER_TYPE_INT (X.690 8.3.2)");
332 root 1.1 }
333    
334 root 1.5 int negative = data [0] & 0x80;
335 root 1.1
336 root 1.5 UV val = negative ? -1 : 0; // copy signbit to all bits
337 root 1.1
338 root 1.23 if (len > UVSIZE + (!negative && !*data))
339 root 1.25 error ("BER_TYPE_INT overflow");
340 root 1.23
341 root 1.5 do
342     val = (val << 8) | *data++;
343     while (--len);
344 root 1.1
345 root 1.6 // the cast to IV relies on implementation-defined behaviour (two's complement cast)
346 root 1.5 // but that's ok, as perl relies on it as well.
347     return negative ? newSViv ((IV)val) : newSVuv (val);
348 root 1.1 }
349    
350     static SV *
351 root 1.30 decode_data (UV len)
352 root 1.1 {
353 root 1.15 return newSVpvn ((char *)get_n (len), len);
354 root 1.1 }
355    
356 root 1.15 // helper for decode_object_identifier
357 root 1.1 static char *
358 root 1.15 write_uv (char *buf, UV u)
359 root 1.1 {
360     // the one-digit case is absolutely predominant, so this pays off (hopefully)
361 root 1.5 if (expect_true (u < 10))
362 root 1.1 *buf++ = u + '0';
363     else
364     {
365 root 1.15 // this *could* be done much faster using branchless fixed-point arithmetics
366 root 1.1 char *beg = buf;
367    
368     do
369     {
370     *buf++ = u % 10 + '0';
371     u /= 10;
372     }
373     while (u);
374    
375     // reverse digits
376 root 1.11 char *ptr = buf;
377 root 1.13 while (--ptr > beg)
378 root 1.1 {
379     char c = *ptr;
380     *ptr = *beg;
381     *beg = c;
382 root 1.11 ++beg;
383 root 1.1 }
384     }
385    
386     return buf;
387     }
388    
389     static SV *
390 root 1.30 decode_oid (UV len, int relative)
391 root 1.1 {
392 root 1.5 if (len <= 0)
393 root 1.1 {
394 root 1.25 error ("BER_TYPE_OID length must not be zero");
395 root 1.1 return &PL_sv_undef;
396     }
397    
398 root 1.5 U8 *end = cur + len;
399 root 1.20 UV w = get_w ();
400 root 1.1
401 root 1.23 static char oid[MAX_OID_STRLEN]; // static, because too large for stack
402 root 1.1 char *app = oid;
403    
404 root 1.5 if (relative)
405     app = write_uv (app, w);
406 root 1.18 else
407     {
408 root 1.27 UV w1, w2;
409    
410     if (w < 2 * 40)
411     (w1 = w / 40), (w2 = w % 40);
412     else
413     (w1 = 2), (w2 = w - 2 * 40);
414    
415     app = write_uv (app, w1);
416 root 1.18 *app++ = '.';
417 root 1.27 app = write_uv (app, w2);
418 root 1.18 }
419 root 1.1
420 root 1.13 while (cur < end)
421 root 1.1 {
422 root 1.13 // we assume an oid component is never > 64 digits
423     if (oid + sizeof (oid) - app < 64)
424     croak ("BER_TYPE_OID to long to decode");
425    
426 root 1.20 w = get_w ();
427 root 1.1 *app++ = '.';
428     app = write_uv (app, w);
429     }
430    
431     return newSVpvn (oid, app - oid);
432     }
433    
434 root 1.33 // oh my, this is a total mess
435     static SV *
436     decode_real (UV len)
437     {
438     SV *res;
439     U8 *beg = cur;
440    
441     if (len == 0)
442     res = newSVnv (0.);
443     else
444     {
445     U8 info = get_u8 ();
446    
447     if (info & 0x80)
448     {
449     // binary
450     static const U8 base[] = { 2, 8, 16, 0 };
451     NV S = info & 0x40 ? -1 : 1; // sign
452     NV B = base [(info >> 4) & 3]; // base
453     NV F = 1 << ((info >> 2) & 3); // scale factor ("shift")
454     int L = info & 3; // exponent length
455    
456     if (!B)
457     croak ("BER_TYPE_REAL binary encoding uses invalid base (0x%02x)", info);
458    
459     SAVETMPS;
460    
461     SV *E = sv_2mortal (decode_int (L == 3 ? get_u8 () : L + 1));
462     SV *M = sv_2mortal (decode_int (len - (cur - beg)));
463    
464     res = newSVnv (S * SvNV (M) * F * Perl_pow (B, SvNV (E)));
465    
466     FREETMPS;
467     }
468     else if (info & 0x40)
469     {
470     // SpecialRealValue
471     U8 special = get_u8 ();
472     NV val;
473    
474     switch (special)
475     {
476     case 0x40: val = NV_INF; break;
477     case 0x41: val = -NV_INF; break;
478     case 0x42: val = NV_NAN; break;
479     case 0x43: val = -(NV)0.; break;
480    
481     default:
482     croak ("BER_TYPE_REAL SpecialRealValues invalid encoding 0x%02x (X.690 8.5.9)", special);
483     }
484    
485     res = newSVnv (val);
486     }
487     else
488     {
489     // decimal
490     dSP;
491     SAVETMPS;
492     PUSHMARK (SP);
493     EXTEND (SP, 2);
494     PUSHs (sv_2mortal (newSVcacheint (info & 0x3f)));
495     PUSHs (sv_2mortal (newSVpvn (get_n (len - 1), len - 1)));
496     PUTBACK;
497     call_pv ("Convert::BER::XS::_decode_real_decimal", G_SCALAR);
498     SPAGAIN;
499     res = SvREFCNT_inc_NN (POPs);
500     PUTBACK;
501     FREETMPS;
502     }
503     }
504    
505     if (cur - beg != len)
506     {
507     SvREFCNT_dec_NN (res);
508     croak ("BER_TYPE_REAL invalid content length (X.690 8,5)");
509     }
510    
511     return res;
512     }
513    
514 root 1.7 // TODO: this is unacceptably slow
515     static SV *
516 root 1.30 decode_ucs (UV len, int chrsize)
517 root 1.7 {
518     if (len & (chrsize - 1))
519     croak ("BER_TYPE_UCS has an invalid number of octets (%d)", len);
520    
521 root 1.30 SV *res = NEWSV (0, 0);
522    
523 root 1.7 while (len)
524     {
525     U8 b1 = get_u8 ();
526     U8 b2 = get_u8 ();
527     U32 chr = (b1 << 8) | b2;
528    
529     if (chrsize == 4)
530     {
531     U8 b3 = get_u8 ();
532     U8 b4 = get_u8 ();
533     chr = (chr << 16) | (b3 << 8) | b4;
534     }
535    
536     U8 uchr [UTF8_MAXBYTES];
537     int uclen = uvuni_to_utf8 (uchr, chr) - uchr;
538    
539     sv_catpvn (res, (const char *)uchr, uclen);
540     len -= chrsize;
541     }
542    
543     SvUTF8_on (res);
544    
545     return res;
546     }
547    
548 root 1.1 static SV *
549 root 1.14 decode_ber (void)
550 root 1.1 {
551 root 1.2 int identifier = get_u8 ();
552 root 1.1
553     SV *res;
554    
555 root 1.5 int constructed = identifier & ASN_CONSTRUCTED;
556     int klass = (identifier & ASN_CLASS_MASK) >> ASN_CLASS_SHIFT;
557     int tag = identifier & ASN_TAG_MASK;
558 root 1.1
559     if (tag == ASN_TAG_BER)
560 root 1.3 tag = get_w ();
561 root 1.1
562     if (constructed)
563     {
564 root 1.31 want (1);
565 root 1.1 AV *av = (AV *)sv_2mortal ((SV *)newAV ());
566    
567 root 1.31 if (expect_false (*cur == 0x80))
568     {
569     // indefinite length
570     ++cur;
571    
572     for (;;)
573     {
574     want (2);
575     if (!cur [0] && !cur [1])
576     {
577     cur += 2;
578     break;
579     }
580    
581     av_push (av, decode_ber ());
582     }
583     }
584     else
585     {
586     UV len = get_length ();
587     UV seqend = (cur - buf) + len;
588 root 1.1
589 root 1.31 while (cur < buf + seqend)
590     av_push (av, decode_ber ());
591    
592     if (expect_false (cur > buf + seqend))
593     croak ("CONSTRUCTED type %02x length overflow (0x%x 0x%x)\n", identifier, (int)(cur - buf), (int)seqend);
594     }
595 root 1.1
596     res = newRV_inc ((SV *)av);
597     }
598     else
599 root 1.30 {
600     UV len = get_length ();
601 root 1.13
602 root 1.30 switch (profile_lookup (cur_profile, klass, tag))
603     {
604     case BER_TYPE_NULL:
605     if (expect_false (len))
606 root 1.20 croak ("BER_TYPE_NULL value with non-zero length %d encountered (X.690 8.8.2)", len);
607 root 1.13
608     res = &PL_sv_undef;
609 root 1.30 break;
610 root 1.1
611 root 1.30 case BER_TYPE_BOOL:
612     if (expect_false (len != 1))
613 root 1.20 croak ("BER_TYPE_BOOLEAN value with invalid length %d encountered (X.690 8.2.1)", len);
614 root 1.5
615 root 1.13 res = newSVcacheint (!!get_u8 ());
616 root 1.30 break;
617 root 1.5
618 root 1.30 case BER_TYPE_OID:
619     res = decode_oid (len, 0);
620     break;
621    
622     case BER_TYPE_RELOID:
623     res = decode_oid (len, 1);
624     break;
625    
626     case BER_TYPE_INT:
627     res = decode_int (len);
628     break;
629    
630     case BER_TYPE_UTF8:
631     res = decode_data (len);
632     SvUTF8_on (res);
633     break;
634    
635     case BER_TYPE_BYTES:
636     res = decode_data (len);
637     break;
638    
639     case BER_TYPE_IPADDRESS:
640     {
641     if (len != 4)
642     croak ("BER_TYPE_IPADDRESS type with invalid length %d encountered (RFC 2578 7.1.5)", len);
643    
644     U8 *data = get_n (4);
645     res = newSVpvf ("%d.%d.%d.%d", data [0], data [1], data [2], data [3]);
646     }
647     break;
648    
649     case BER_TYPE_UCS2:
650     res = decode_ucs (len, 2);
651     break;
652    
653     case BER_TYPE_UCS4:
654     res = decode_ucs (len, 4);
655     break;
656 root 1.1
657 root 1.30 case BER_TYPE_REAL:
658 root 1.33 res = decode_real (len);
659     break;
660 root 1.1
661 root 1.30 case BER_TYPE_CROAK:
662     croak ("class/tag %d/%d mapped to BER_TYPE_CROAK", klass, tag);
663 root 1.1
664 root 1.30 default:
665     croak ("unconfigured/unsupported class/tag %d/%d", klass, tag);
666     }
667     }
668 root 1.1
669     AV *av = newAV ();
670     av_fill (av, BER_ARRAYSIZE - 1);
671 root 1.16 AvARRAY (av)[BER_CLASS] = newSVcacheint (klass);
672     AvARRAY (av)[BER_TAG ] = newSVcacheint (tag);
673     AvARRAY (av)[BER_FLAGS] = newSVcacheint (constructed ? 1 : 0);
674     AvARRAY (av)[BER_DATA ] = res;
675 root 1.1
676     return newRV_noinc ((SV *)av);
677     }
678    
679 root 1.3 /////////////////////////////////////////////////////////////////////////////
680     // encoder
681    
682     /* adds two STRLENs together, slow, and with paranoia */
683     static STRLEN
684     strlen_sum (STRLEN l1, STRLEN l2)
685     {
686     size_t sum = l1 + l2;
687    
688     if (sum < (size_t)l2 || sum != (size_t)(STRLEN)sum)
689 root 1.20 croak ("Convert::BER::XS: string size overflow");
690 root 1.3
691     return sum;
692     }
693    
694     static void
695     set_buf (SV *sv)
696     {
697     STRLEN len;
698     buf_sv = sv;
699 root 1.10 buf = (U8 *)SvPVbyte (buf_sv, len);
700 root 1.3 cur = buf;
701     end = buf + len;
702     }
703    
704     /* similar to SvGROW, but somewhat safer and guarantees exponential realloc strategy */
705     static char *
706     my_sv_grow (SV *sv, size_t len1, size_t len2)
707     {
708     len1 = strlen_sum (len1, len2);
709     len1 = strlen_sum (len1, len1 >> 1);
710    
711     if (len1 > 4096 - 24)
712     len1 = (len1 | 4095) - 24;
713    
714     return SvGROW (sv, len1);
715     }
716    
717     static void
718     need (STRLEN len)
719     {
720     if (expect_false ((uintptr_t)(end - cur) < len))
721     {
722     STRLEN pos = cur - buf;
723 root 1.10 buf = (U8 *)my_sv_grow (buf_sv, pos, len);
724 root 1.3 cur = buf + pos;
725     end = buf + SvLEN (buf_sv) - 1;
726     }
727     }
728    
729     static void
730     put_u8 (int val)
731     {
732     need (1);
733     *cur++ = val;
734     }
735    
736     static void
737 root 1.15 put_w_nocheck (UV val)
738 root 1.3 {
739 root 1.15 #if UVSIZE > 4
740     *cur = (val >> 7 * 9) | 0x80; cur += val >= ((UV)1 << (7 * 9));
741     *cur = (val >> 7 * 8) | 0x80; cur += val >= ((UV)1 << (7 * 8));
742     *cur = (val >> 7 * 7) | 0x80; cur += val >= ((UV)1 << (7 * 7));
743     *cur = (val >> 7 * 6) | 0x80; cur += val >= ((UV)1 << (7 * 6));
744     *cur = (val >> 7 * 5) | 0x80; cur += val >= ((UV)1 << (7 * 5));
745     #endif
746     *cur = (val >> 7 * 4) | 0x80; cur += val >= ((UV)1 << (7 * 4));
747     *cur = (val >> 7 * 3) | 0x80; cur += val >= ((UV)1 << (7 * 3));
748     *cur = (val >> 7 * 2) | 0x80; cur += val >= ((UV)1 << (7 * 2));
749     *cur = (val >> 7 * 1) | 0x80; cur += val >= ((UV)1 << (7 * 1));
750 root 1.3 *cur = val & 0x7f; cur += 1;
751     }
752    
753     static void
754 root 1.15 put_w (UV val)
755 root 1.3 {
756     need (5); // we only handle up to 5 bytes
757    
758     put_w_nocheck (val);
759     }
760    
761     static U8 *
762 root 1.15 put_length_at (UV val, U8 *cur)
763 root 1.3 {
764 root 1.29 if (val <= 0x7fU)
765 root 1.3 *cur++ = val;
766     else
767     {
768     U8 *lenb = cur++;
769    
770 root 1.15 #if UVSIZE > 4
771 root 1.28 *cur = val >> 56; cur += val >= ((UV)1 << (8 * 7));
772     *cur = val >> 48; cur += val >= ((UV)1 << (8 * 6));
773     *cur = val >> 40; cur += val >= ((UV)1 << (8 * 5));
774     *cur = val >> 32; cur += val >= ((UV)1 << (8 * 4));
775 root 1.15 #endif
776 root 1.28 *cur = val >> 24; cur += val >= ((UV)1 << (8 * 3));
777     *cur = val >> 16; cur += val >= ((UV)1 << (8 * 2));
778     *cur = val >> 8; cur += val >= ((UV)1 << (8 * 1));
779 root 1.3 *cur = val ; cur += 1;
780    
781     *lenb = 0x80 + cur - lenb - 1;
782     }
783    
784     return cur;
785     }
786    
787     static void
788 root 1.15 put_length (UV val)
789 root 1.3 {
790 root 1.29 need (9 + val);
791 root 1.3 cur = put_length_at (val, cur);
792     }
793    
794     // return how many bytes the encoded length requires
795 root 1.15 static int length_length (UV val)
796 root 1.3 {
797 root 1.29 // use hashing with a DeBruin sequence, anyone?
798     return expect_true (val <= 0x7fU)
799 root 1.3 ? 1
800 root 1.15 : 2
801 root 1.29 + (val > 0x000000000000ffU)
802     + (val > 0x0000000000ffffU)
803     + (val > 0x00000000ffffffU)
804 root 1.15 #if UVSIZE > 4
805 root 1.29 + (val > 0x000000ffffffffU)
806     + (val > 0x0000ffffffffffU)
807     + (val > 0x00ffffffffffffU)
808 root 1.15 + (val > 0xffffffffffffffU)
809     #endif
810     ;
811 root 1.3 }
812    
813     static void
814 root 1.5 encode_data (const char *ptr, STRLEN len)
815 root 1.3 {
816     put_length (len);
817     memcpy (cur, ptr, len);
818     cur += len;
819     }
820    
821     static void
822 root 1.5 encode_uv (UV uv)
823     {
824     }
825    
826     static void
827     encode_int (SV *sv)
828 root 1.3 {
829 root 1.5 need (8 + 1 + 1); // 64 bit + length + extra 0
830    
831     if (expect_false (!SvIOK (sv)))
832     sv_2iv_flags (sv, 0);
833 root 1.3
834     U8 *lenb = cur++;
835    
836 root 1.5 if (SvIOK_notUV (sv))
837 root 1.3 {
838 root 1.5 IV iv = SvIVX (sv);
839    
840     if (expect_false (iv < 0))
841     {
842     // get two's complement bit pattern - works even on hypothetical non-2c machines
843     UV uv = iv;
844    
845     #if UVSIZE > 4
846     *cur = uv >> 56; cur += !!(~uv & 0xff80000000000000U);
847     *cur = uv >> 48; cur += !!(~uv & 0xffff800000000000U);
848     *cur = uv >> 40; cur += !!(~uv & 0xffffff8000000000U);
849     *cur = uv >> 32; cur += !!(~uv & 0xffffffff80000000U);
850     #endif
851     *cur = uv >> 24; cur += !!(~uv & 0xffffffffff800000U);
852     *cur = uv >> 16; cur += !!(~uv & 0xffffffffffff8000U);
853     *cur = uv >> 8; cur += !!(~uv & 0xffffffffffffff80U);
854     *cur = uv ; cur += 1;
855    
856     *lenb = cur - lenb - 1;
857 root 1.3
858 root 1.5 return;
859     }
860 root 1.3 }
861    
862 root 1.5 UV uv = SvUV (sv);
863 root 1.3
864 root 1.5 // prepend an extra 0 if the high bit is 1
865     *cur = 0; cur += !!(uv & ((UV)1 << (UVSIZE * 8 - 1)));
866 root 1.3
867 root 1.5 #if UVSIZE > 4
868     *cur = uv >> 56; cur += !!(uv & 0xff80000000000000U);
869     *cur = uv >> 48; cur += !!(uv & 0xffff800000000000U);
870     *cur = uv >> 40; cur += !!(uv & 0xffffff8000000000U);
871     *cur = uv >> 32; cur += !!(uv & 0xffffffff80000000U);
872     #endif
873     *cur = uv >> 24; cur += !!(uv & 0xffffffffff800000U);
874     *cur = uv >> 16; cur += !!(uv & 0xffffffffffff8000U);
875     *cur = uv >> 8; cur += !!(uv & 0xffffffffffffff80U);
876 root 1.3 *cur = uv ; cur += 1;
877    
878     *lenb = cur - lenb - 1;
879     }
880    
881     // we don't know the length yet, so we optimistically
882 root 1.15 // assume the length will need one octet later. If that
883     // turns out to be wrong, we memmove as needed.
884 root 1.3 // mark the beginning
885     static STRLEN
886 root 1.14 len_fixup_mark (void)
887 root 1.3 {
888     return cur++ - buf;
889     }
890    
891     // patch up the length
892     static void
893     len_fixup (STRLEN mark)
894     {
895     STRLEN reallen = (cur - buf) - mark - 1;
896     int lenlen = length_length (reallen);
897    
898     if (expect_false (lenlen > 1))
899     {
900     // bad luck, we have to shift the bytes to make room for the length
901     need (5);
902     memmove (buf + mark + lenlen, buf + mark + 1, reallen);
903     cur += lenlen - 1;
904     }
905    
906     put_length_at (reallen, buf + mark);
907     }
908    
909     static char *
910     read_uv (char *str, UV *uv)
911     {
912     UV r = 0;
913    
914     while (*str >= '0')
915     r = r * 10 + *str++ - '0';
916    
917     *uv = r;
918    
919     str += !!*str; // advance over any non-zero byte
920    
921     return str;
922     }
923    
924     static void
925 root 1.5 encode_oid (SV *oid, int relative)
926 root 1.3 {
927 root 1.5 STRLEN len;
928     char *ptr = SvPV (oid, len); // utf8 vs. bytes does not matter
929 root 1.3
930     // we need at most as many octets as the string form
931 root 1.5 need (len + 1);
932 root 1.3 STRLEN mark = len_fixup_mark ();
933    
934     UV w1, w2;
935    
936 root 1.5 if (!relative)
937     {
938     ptr = read_uv (ptr, &w1);
939     ptr = read_uv (ptr, &w2);
940 root 1.3
941 root 1.5 put_w_nocheck (w1 * 40 + w2);
942     }
943 root 1.3
944     while (*ptr)
945     {
946     ptr = read_uv (ptr, &w1);
947     put_w_nocheck (w1);
948     }
949    
950     len_fixup (mark);
951     }
952    
953 root 1.33 static void
954     encode_real (SV *data)
955 root 1.3 {
956 root 1.33 NV nv = SvNV (data);
957 root 1.4
958 root 1.33 if (expect_false (nv == (NV)0.))
959     {
960     if (signbit (nv))
961     {
962     // negative zero
963     need (3);
964     *cur++ = 2;
965     *cur++ = 0x40;
966     *cur++ = 0x43;
967     }
968     else
969     {
970     // positive zero
971     need (1);
972     *cur++ = 0;
973     }
974     }
975     else if (expect_false (Perl_isinf (nv)))
976     {
977     need (3);
978     *cur++ = 2;
979     *cur++ = 0x40;
980     *cur++ = nv < (NV)0. ? 0x41 : 0x40;
981     }
982     else if (expect_false (Perl_isnan (nv)))
983     {
984     need (3);
985     *cur++ = 2;
986     *cur++ = 0x40;
987     *cur++ = 0x42;
988     }
989     else
990     {
991     // use decimal encoding
992     dSP;
993     SAVETMPS;
994     PUSHMARK (SP);
995     EXTEND (SP, 2);
996     PUSHs (data);
997     PUSHs (sv_2mortal (newSVcacheint (NV_DIG)));
998     PUTBACK;
999     call_pv ("Convert::BER::XS::_encode_real_decimal", G_SCALAR);
1000     SPAGAIN;
1001    
1002     SV *sv = POPs;
1003     STRLEN l;
1004     char *f = SvPV (sv, l);
1005    
1006     put_length (l);
1007     memcpy (cur, f, l);
1008     cur += l;
1009 root 1.3
1010 root 1.33 PUTBACK;
1011     FREETMPS;
1012     }
1013 root 1.4 }
1014    
1015     static void
1016 root 1.7 encode_ucs (SV *data, int chrsize)
1017     {
1018     STRLEN uchars = sv_len_utf8 (data);
1019     STRLEN len;;
1020     char *ptr = SvPVutf8 (data, len);
1021    
1022     put_length (uchars * chrsize);
1023    
1024     while (uchars--)
1025     {
1026     STRLEN uclen;
1027 root 1.10 UV uchr = utf8_to_uvchr_buf ((U8 *)ptr, (U8 *)ptr + len, &uclen);
1028 root 1.7
1029     ptr += uclen;
1030     len -= uclen;
1031    
1032     if (chrsize == 4)
1033     {
1034     *cur++ = uchr >> 24;
1035     *cur++ = uchr >> 16;
1036     }
1037    
1038     *cur++ = uchr >> 8;
1039     *cur++ = uchr;
1040     }
1041     }
1042 root 1.33
1043     // check whether an SV is a BER tuple and returns its AV *
1044     static AV *
1045     ber_tuple (SV *tuple)
1046     {
1047     SV *rv;
1048    
1049     if (expect_false (!SvROK (tuple) || SvTYPE ((rv = SvRV (tuple))) != SVt_PVAV))
1050     croak ("BER tuple must be array-reference");
1051    
1052     if (expect_false (SvRMAGICAL (rv)))
1053     croak ("BER tuple must not be tied");
1054    
1055     if (expect_false (AvFILL ((AV *)rv) != BER_ARRAYSIZE - 1))
1056     croak ("BER tuple must contain exactly %d elements, not %d", BER_ARRAYSIZE, AvFILL ((AV *)rv) + 1);
1057    
1058     return (AV *)rv;
1059     }
1060    
1061 root 1.7 static void
1062 root 1.4 encode_ber (SV *tuple)
1063     {
1064     AV *av = ber_tuple (tuple);
1065 root 1.3
1066     int klass = SvIV (AvARRAY (av)[BER_CLASS]);
1067     int tag = SvIV (AvARRAY (av)[BER_TAG]);
1068 root 1.16 int constructed = SvIV (AvARRAY (av)[BER_FLAGS]) & 1 ? ASN_CONSTRUCTED : 0;
1069 root 1.3 SV *data = AvARRAY (av)[BER_DATA];
1070    
1071     int identifier = (klass << ASN_CLASS_SHIFT) | constructed;
1072    
1073     if (expect_false (tag >= ASN_TAG_BER))
1074     {
1075     put_u8 (identifier | ASN_TAG_BER);
1076     put_w (tag);
1077     }
1078     else
1079     put_u8 (identifier | tag);
1080    
1081     if (constructed)
1082     {
1083     // we optimistically assume that only one length byte is needed
1084     // and adjust later
1085     need (1);
1086     STRLEN mark = len_fixup_mark ();
1087    
1088     if (expect_false (!SvROK (data) || SvTYPE (SvRV (data)) != SVt_PVAV))
1089 root 1.25 croak ("BER CONSTRUCTED data must be array-reference");
1090 root 1.3
1091     AV *av = (AV *)SvRV (data);
1092     int fill = AvFILL (av);
1093    
1094     if (expect_false (SvRMAGICAL (av)))
1095 root 1.25 croak ("BER CONSTRUCTED data must not be tied");
1096 root 1.3
1097 root 1.11 int i;
1098     for (i = 0; i <= fill; ++i)
1099 root 1.3 encode_ber (AvARRAY (av)[i]);
1100    
1101     len_fixup (mark);
1102     }
1103     else
1104 root 1.5 switch (profile_lookup (cur_profile, klass, tag))
1105 root 1.3 {
1106 root 1.5 case BER_TYPE_NULL:
1107 root 1.3 put_length (0);
1108     break;
1109    
1110 root 1.5 case BER_TYPE_BOOL:
1111     put_length (1);
1112 root 1.17 *cur++ = SvTRUE (data) ? 0xff : 0x00; // 0xff = DER/CER
1113 root 1.3 break;
1114    
1115 root 1.5 case BER_TYPE_OID:
1116     encode_oid (data, 0);
1117 root 1.3 break;
1118    
1119 root 1.5 case BER_TYPE_RELOID:
1120     encode_oid (data, 1);
1121 root 1.3 break;
1122    
1123 root 1.5 case BER_TYPE_INT:
1124     encode_int (data);
1125     break;
1126    
1127     case BER_TYPE_BYTES:
1128     {
1129     STRLEN len;
1130     const char *ptr = SvPVbyte (data, len);
1131     encode_data (ptr, len);
1132     }
1133     break;
1134    
1135     case BER_TYPE_UTF8:
1136     {
1137     STRLEN len;
1138     const char *ptr = SvPVutf8 (data, len);
1139     encode_data (ptr, len);
1140     }
1141     break;
1142    
1143 root 1.6 case BER_TYPE_IPADDRESS:
1144     {
1145     U8 ip[4];
1146     sscanf (SvPV_nolen (data), "%hhu.%hhu.%hhu.%hhu", ip + 0, ip + 1, ip + 2, ip + 3);
1147     encode_data ((const char *)ip, sizeof (ip));
1148     }
1149     break;
1150    
1151 root 1.5 case BER_TYPE_UCS2:
1152 root 1.7 encode_ucs (data, 2);
1153     break;
1154    
1155 root 1.5 case BER_TYPE_UCS4:
1156 root 1.7 encode_ucs (data, 4);
1157     break;
1158    
1159     case BER_TYPE_REAL:
1160 root 1.33 encode_real (data);
1161     break;
1162 root 1.25
1163 root 1.5 case BER_TYPE_CROAK:
1164 root 1.25 croak ("class/tag %d/%d mapped to BER_TYPE_CROAK", klass, tag);
1165    
1166 root 1.3 default:
1167 root 1.5 croak ("unconfigured/unsupported class/tag %d/%d", klass, tag);
1168 root 1.3 }
1169    
1170     }
1171    
1172     /////////////////////////////////////////////////////////////////////////////
1173    
1174 root 1.1 MODULE = Convert::BER::XS PACKAGE = Convert::BER::XS
1175    
1176     PROTOTYPES: ENABLE
1177    
1178     BOOT:
1179     {
1180     HV *stash = gv_stashpv ("Convert::BER::XS", 1);
1181    
1182 root 1.5 profile_stash = gv_stashpv ("Convert::BER::XS::Profile", 1);
1183    
1184 root 1.1 static const struct {
1185     const char *name;
1186     IV iv;
1187     } *civ, const_iv[] = {
1188 root 1.5 #define const_iv(name) { # name, name },
1189     const_iv (ASN_BOOLEAN)
1190 root 1.15 const_iv (ASN_INTEGER)
1191 root 1.5 const_iv (ASN_BIT_STRING)
1192     const_iv (ASN_OCTET_STRING)
1193     const_iv (ASN_NULL)
1194     const_iv (ASN_OBJECT_IDENTIFIER)
1195     const_iv (ASN_OBJECT_DESCRIPTOR)
1196     const_iv (ASN_OID)
1197     const_iv (ASN_EXTERNAL)
1198     const_iv (ASN_REAL)
1199     const_iv (ASN_SEQUENCE)
1200     const_iv (ASN_ENUMERATED)
1201     const_iv (ASN_EMBEDDED_PDV)
1202     const_iv (ASN_UTF8_STRING)
1203     const_iv (ASN_RELATIVE_OID)
1204     const_iv (ASN_SET)
1205     const_iv (ASN_NUMERIC_STRING)
1206     const_iv (ASN_PRINTABLE_STRING)
1207     const_iv (ASN_TELETEX_STRING)
1208     const_iv (ASN_T61_STRING)
1209     const_iv (ASN_VIDEOTEX_STRING)
1210     const_iv (ASN_IA5_STRING)
1211     const_iv (ASN_ASCII_STRING)
1212     const_iv (ASN_UTC_TIME)
1213     const_iv (ASN_GENERALIZED_TIME)
1214     const_iv (ASN_GRAPHIC_STRING)
1215     const_iv (ASN_VISIBLE_STRING)
1216     const_iv (ASN_ISO646_STRING)
1217     const_iv (ASN_GENERAL_STRING)
1218     const_iv (ASN_UNIVERSAL_STRING)
1219     const_iv (ASN_CHARACTER_STRING)
1220     const_iv (ASN_BMP_STRING)
1221    
1222     const_iv (ASN_UNIVERSAL)
1223     const_iv (ASN_APPLICATION)
1224     const_iv (ASN_CONTEXT)
1225     const_iv (ASN_PRIVATE)
1226    
1227     const_iv (BER_CLASS)
1228     const_iv (BER_TAG)
1229 root 1.16 const_iv (BER_FLAGS)
1230 root 1.5 const_iv (BER_DATA)
1231    
1232     const_iv (BER_TYPE_BYTES)
1233     const_iv (BER_TYPE_UTF8)
1234     const_iv (BER_TYPE_UCS2)
1235     const_iv (BER_TYPE_UCS4)
1236     const_iv (BER_TYPE_INT)
1237     const_iv (BER_TYPE_OID)
1238     const_iv (BER_TYPE_RELOID)
1239     const_iv (BER_TYPE_NULL)
1240     const_iv (BER_TYPE_BOOL)
1241     const_iv (BER_TYPE_REAL)
1242 root 1.6 const_iv (BER_TYPE_IPADDRESS)
1243 root 1.5 const_iv (BER_TYPE_CROAK)
1244    
1245     const_iv (SNMP_IPADDRESS)
1246     const_iv (SNMP_COUNTER32)
1247 root 1.21 const_iv (SNMP_GAUGE32)
1248 root 1.5 const_iv (SNMP_UNSIGNED32)
1249     const_iv (SNMP_TIMETICKS)
1250     const_iv (SNMP_OPAQUE)
1251     const_iv (SNMP_COUNTER64)
1252 root 1.1 };
1253    
1254     for (civ = const_iv + sizeof (const_iv) / sizeof (const_iv [0]); civ > const_iv; civ--)
1255     newCONSTSUB (stash, (char *)civ[-1].name, newSViv (civ[-1].iv));
1256     }
1257    
1258 root 1.22 void
1259 root 1.5 ber_decode (SV *ber, SV *profile = &PL_sv_undef)
1260 root 1.22 ALIAS:
1261     ber_decode_prefix = 1
1262     PPCODE:
1263 root 1.1 {
1264 root 1.5 cur_profile = SvPROFILE (profile);
1265 root 1.3 STRLEN len;
1266 root 1.10 buf = (U8 *)SvPVbyte (ber, len);
1267 root 1.1 cur = buf;
1268 root 1.3 end = buf + len;
1269 root 1.1
1270 root 1.33 PUTBACK;
1271 root 1.22 SV *tuple = decode_ber ();
1272 root 1.33 SPAGAIN;
1273 root 1.22
1274     EXTEND (SP, 2);
1275     PUSHs (sv_2mortal (tuple));
1276    
1277     if (ix)
1278     PUSHs (sv_2mortal (newSViv (cur - buf)));
1279     else if (cur != end)
1280 root 1.25 error ("trailing garbage after BER value");
1281 root 1.1 }
1282    
1283     void
1284 root 1.16 ber_is (SV *tuple, SV *klass = &PL_sv_undef, SV *tag = &PL_sv_undef, SV *flags = &PL_sv_undef, SV *data = &PL_sv_undef)
1285 root 1.1 PPCODE:
1286     {
1287     if (!SvOK (tuple))
1288     XSRETURN_NO;
1289    
1290     if (!SvROK (tuple) || SvTYPE (SvRV (tuple)) != SVt_PVAV)
1291 root 1.4 croak ("ber_is: tuple must be BER tuple (array-ref)");
1292 root 1.1
1293     AV *av = (AV *)SvRV (tuple);
1294    
1295     XPUSHs (
1296 root 1.16 (!SvOK (klass) || SvIV (AvARRAY (av)[BER_CLASS]) == SvIV (klass))
1297     && (!SvOK (tag) || SvIV (AvARRAY (av)[BER_TAG ]) == SvIV (tag))
1298     && (!SvOK (flags) || !SvIV (AvARRAY (av)[BER_FLAGS]) == !SvIV (flags))
1299     && (!SvOK (data) || sv_eq (AvARRAY (av)[BER_DATA ], data))
1300 root 1.4 ? &PL_sv_yes : &PL_sv_undef);
1301 root 1.1 }
1302    
1303     void
1304     ber_is_seq (SV *tuple)
1305     PPCODE:
1306     {
1307     if (!SvOK (tuple))
1308     XSRETURN_UNDEF;
1309    
1310 root 1.4 AV *av = ber_tuple (tuple);
1311 root 1.1
1312     XPUSHs (
1313 root 1.16 SvIV (AvARRAY (av)[BER_CLASS]) == ASN_UNIVERSAL
1314     && SvIV (AvARRAY (av)[BER_TAG ]) == ASN_SEQUENCE
1315     && SvIV (AvARRAY (av)[BER_FLAGS])
1316 root 1.1 ? AvARRAY (av)[BER_DATA] : &PL_sv_undef);
1317     }
1318    
1319     void
1320 root 1.15 ber_is_int (SV *tuple, SV *value = &PL_sv_undef)
1321 root 1.1 PPCODE:
1322     {
1323     if (!SvOK (tuple))
1324     XSRETURN_NO;
1325    
1326 root 1.4 AV *av = ber_tuple (tuple);
1327 root 1.1
1328 root 1.15 UV data = SvUV (AvARRAY (av)[BER_DATA]);
1329 root 1.1
1330     XPUSHs (
1331 root 1.16 SvIV (AvARRAY (av)[BER_CLASS]) == ASN_UNIVERSAL
1332     && SvIV (AvARRAY (av)[BER_TAG ]) == ASN_INTEGER
1333     && !SvIV (AvARRAY (av)[BER_FLAGS])
1334 root 1.15 && (!SvOK (value) || data == SvUV (value))
1335     ? sv_2mortal (data ? newSVsv (AvARRAY (av)[BER_DATA]) : newSVpv ("0 but true", 0))
1336 root 1.4 : &PL_sv_undef);
1337 root 1.1 }
1338    
1339     void
1340 root 1.4 ber_is_oid (SV *tuple, SV *oid = &PL_sv_undef)
1341 root 1.1 PPCODE:
1342     {
1343     if (!SvOK (tuple))
1344     XSRETURN_NO;
1345    
1346 root 1.4 AV *av = ber_tuple (tuple);
1347 root 1.1
1348     XPUSHs (
1349 root 1.16 SvIV (AvARRAY (av)[BER_CLASS]) == ASN_UNIVERSAL
1350     && SvIV (AvARRAY (av)[BER_TAG ]) == ASN_OBJECT_IDENTIFIER
1351     && !SvIV (AvARRAY (av)[BER_FLAGS])
1352 root 1.4 && (!SvOK (oid) || sv_eq (AvARRAY (av)[BER_DATA], oid))
1353     ? newSVsv (AvARRAY (av)[BER_DATA]) : &PL_sv_undef);
1354 root 1.1 }
1355    
1356 root 1.3 #############################################################################
1357    
1358     void
1359 root 1.5 ber_encode (SV *tuple, SV *profile = &PL_sv_undef)
1360 root 1.3 PPCODE:
1361     {
1362 root 1.5 cur_profile = SvPROFILE (profile);
1363 root 1.3 buf_sv = sv_2mortal (NEWSV (0, 256));
1364     SvPOK_only (buf_sv);
1365     set_buf (buf_sv);
1366    
1367 root 1.33 PUTBACK;
1368 root 1.3 encode_ber (tuple);
1369 root 1.33 SPAGAIN;
1370 root 1.3
1371     SvCUR_set (buf_sv, cur - buf);
1372     XPUSHs (buf_sv);
1373     }
1374    
1375 root 1.4 SV *
1376 root 1.15 ber_int (SV *sv)
1377 root 1.4 CODE:
1378     {
1379     AV *av = newAV ();
1380     av_fill (av, BER_ARRAYSIZE - 1);
1381 root 1.16 AvARRAY (av)[BER_CLASS] = newSVcacheint (ASN_UNIVERSAL);
1382     AvARRAY (av)[BER_TAG ] = newSVcacheint (ASN_INTEGER);
1383     AvARRAY (av)[BER_FLAGS] = newSVcacheint (0);
1384     AvARRAY (av)[BER_DATA ] = newSVsv (sv);
1385 root 1.4 RETVAL = newRV_noinc ((SV *)av);
1386     }
1387     OUTPUT: RETVAL
1388    
1389     # TODO: not arrayref, but elements?
1390     SV *
1391     ber_seq (SV *arrayref)
1392     CODE:
1393     {
1394     AV *av = newAV ();
1395     av_fill (av, BER_ARRAYSIZE - 1);
1396 root 1.16 AvARRAY (av)[BER_CLASS] = newSVcacheint (ASN_UNIVERSAL);
1397     AvARRAY (av)[BER_TAG ] = newSVcacheint (ASN_SEQUENCE);
1398     AvARRAY (av)[BER_FLAGS] = newSVcacheint (1);
1399     AvARRAY (av)[BER_DATA ] = newSVsv (arrayref);
1400 root 1.4 RETVAL = newRV_noinc ((SV *)av);
1401     }
1402     OUTPUT: RETVAL
1403    
1404 root 1.5 MODULE = Convert::BER::XS PACKAGE = Convert::BER::XS::Profile
1405    
1406     SV *
1407     new (SV *klass)
1408     CODE:
1409     RETVAL = profile_new ();
1410     OUTPUT: RETVAL
1411    
1412 root 1.6 void
1413     set (SV *profile, int klass, int tag, int type)
1414     CODE:
1415     profile_set (SvPROFILE (profile), klass, tag, type);
1416    
1417     IV
1418     get (SV *profile, int klass, int tag)
1419     CODE:
1420     RETVAL = profile_lookup (SvPROFILE (profile), klass, tag);
1421     OUTPUT: RETVAL
1422    
1423     void
1424     _set_default (SV *profile)
1425     CODE:
1426     default_profile = SvPROFILE (profile);
1427    
1428