ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Convert-BER-XS/XS.xs
Revision: 1.6
Committed: Sat Apr 20 01:03:59 2019 UTC (5 years, 1 month ago) by root
Branch: MAIN
Changes since 1.5: +46 -13 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 root 1.5 ASN_BMP_STRING = 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 root 1.5 ASN_APPLICATION = 0x01,
51     ASN_CONTEXT = 0x02,
52     ASN_PRIVATE = 0x03,
53 root 1.1
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 root 1.5 BER_TYPE_BYTES,
68     BER_TYPE_UTF8,
69     BER_TYPE_UCS2,
70     BER_TYPE_UCS4,
71     BER_TYPE_INT,
72     BER_TYPE_OID,
73     BER_TYPE_RELOID,
74     BER_TYPE_NULL,
75     BER_TYPE_BOOL,
76     BER_TYPE_REAL,
77 root 1.6 BER_TYPE_IPADDRESS,
78 root 1.5 BER_TYPE_CROAK,
79     };
80    
81     enum {
82 root 1.1 BER_CLASS = 0,
83     BER_TAG = 1,
84     BER_CONSTRUCTED = 2,
85     BER_DATA = 3,
86     BER_ARRAYSIZE
87     };
88    
89     #define MAX_OID_STRLEN 4096
90    
91 root 1.5 typedef void profile_type;
92    
93     static profile_type *cur_profile, *default_profile;
94 root 1.3 static SV *buf_sv; // encoding buffer
95     static U8 *buf, *cur, *end; // buffer start, current, end
96    
97     #if __GNUC__ >= 3
98     # define expect(expr,value) __builtin_expect ((expr), (value))
99     # define INLINE static inline
100     #else
101     # define expect(expr,value) (expr)
102     # define INLINE static
103     #endif
104    
105     #define expect_false(expr) expect ((expr) != 0, 0)
106     #define expect_true(expr) expect ((expr) != 0, 1)
107 root 1.1
108 root 1.5 /////////////////////////////////////////////////////////////////////////////
109    
110     static SV *sviv_cache[32];
111    
112 root 1.1 // for "small" integers, return a readonly sv, otherwise create a new one
113     static SV *newSVcacheint (int val)
114     {
115 root 1.5 if (expect_false (val < 0 || val >= sizeof (sviv_cache)))
116 root 1.1 return newSViv (val);
117    
118 root 1.5 if (expect_false (!sviv_cache [val]))
119 root 1.1 {
120 root 1.5 sviv_cache [val] = newSVuv (val);
121     SvREADONLY_on (sviv_cache [val]);
122 root 1.1 }
123    
124 root 1.5 return SvREFCNT_inc_NN (sviv_cache [val]);
125     }
126    
127     /////////////////////////////////////////////////////////////////////////////
128    
129     static HV *profile_stash;
130    
131     static profile_type *
132     SvPROFILE (SV *profile)
133     {
134     if (!SvOK (profile))
135 root 1.6 return default_profile;
136 root 1.5
137     if (!SvROK (profile))
138     croak ("invalid profile");
139    
140     profile = SvRV (profile);
141    
142     if (SvSTASH (profile) != profile_stash)
143     croak ("invalid profile object");
144    
145     return (void *)profile;
146     }
147    
148     static int
149     profile_lookup (profile_type *profile, int klass, int tag)
150     {
151     SV *sv = (SV *)profile;
152     U32 idx = (tag << 2) + klass;
153    
154     if (expect_false (idx >= SvCUR (sv)))
155     return BER_TYPE_BYTES;
156    
157     return SvPVX (sv)[idx];
158     }
159    
160     static int
161     profile_set (profile_type *profile, int klass, int tag, int type)
162     {
163     SV *sv = (SV *)profile;
164     U32 idx = (tag << 2) + klass;
165     STRLEN oldlen = SvCUR (sv);
166     STRLEN newlen = idx + 2;
167    
168     if (idx >= oldlen)
169     {
170     sv_grow (sv, newlen);
171     memset (SvPVX (sv) + oldlen, BER_TYPE_BYTES, newlen - oldlen);
172     SvCUR_set (sv, newlen);
173     }
174    
175     SvPVX (sv)[idx] = type;
176     }
177    
178     static SV *
179     profile_new ()
180     {
181     SV *sv = newSVpvn ("", 0);
182    
183     static const struct {
184     int klass;
185     int tag;
186     int type;
187     } *celem, default_map[] = {
188     { ASN_UNIVERSAL, ASN_BOOLEAN , BER_TYPE_BOOL },
189     { ASN_UNIVERSAL, ASN_INTEGER32 , BER_TYPE_INT },
190     { ASN_UNIVERSAL, ASN_NULL , BER_TYPE_NULL },
191     { ASN_UNIVERSAL, ASN_OBJECT_IDENTIFIER, BER_TYPE_OID },
192     { ASN_UNIVERSAL, ASN_OBJECT_DESCRIPTOR, BER_TYPE_OID },
193     { ASN_UNIVERSAL, ASN_RELATIVE_OID , BER_TYPE_RELOID },
194     { ASN_UNIVERSAL, ASN_REAL , BER_TYPE_REAL },
195     { ASN_UNIVERSAL, ASN_UTF8_STRING , BER_TYPE_UTF8 },
196     { ASN_UNIVERSAL, ASN_BMP_STRING , BER_TYPE_UCS2 },
197     { ASN_UNIVERSAL, ASN_UNIVERSAL_STRING , BER_TYPE_UCS4 },
198     };
199    
200     for (celem = default_map + sizeof (default_map) / sizeof (default_map [0]); celem > default_map; celem--)
201     profile_set ((void *)sv, celem->klass, celem->tag, celem->type);
202    
203     return sv_bless (newRV_noinc (sv), profile_stash);
204 root 1.1 }
205    
206     /////////////////////////////////////////////////////////////////////////////
207 root 1.3 // decoder
208 root 1.1
209     static void
210     error (const char *errmsg)
211     {
212     croak ("%s at offset 0x%04x", errmsg, cur - buf);
213     }
214    
215 root 1.3 static void
216     want (UV count)
217 root 1.1 {
218 root 1.3 if (expect_false ((uintptr_t)(end - cur) < count))
219     error ("unexpected end of message buffer");
220 root 1.1 }
221    
222 root 1.2 // get_* functions fetch something from the buffer
223     // decode_* functions use get_* fun ctions to decode ber values
224    
225 root 1.3 // get n octets
226 root 1.1 static U8 *
227 root 1.3 get_n (UV count)
228 root 1.1 {
229 root 1.3 want (count);
230 root 1.1 U8 *res = cur;
231     cur += count;
232     return res;
233     }
234    
235 root 1.3 // get single octet
236 root 1.1 static U8
237 root 1.2 get_u8 (void)
238 root 1.1 {
239 root 1.3 if (cur == end)
240     error ("unexpected end of message buffer");
241 root 1.1
242     return *cur++;
243     }
244    
245 root 1.3 // get ber-encoded integer (i.e. pack "w")
246 root 1.1 static U32
247 root 1.3 get_w (void)
248 root 1.1 {
249     U32 res = 0;
250    
251     for (;;)
252     {
253 root 1.2 U8 c = get_u8 ();
254 root 1.1 res = (res << 7) | (c & 0x7f);
255    
256     if (!(c & 0x80))
257     return res;
258     }
259     }
260    
261     static U32
262 root 1.2 get_length (void)
263 root 1.1 {
264 root 1.2 U32 res = get_u8 ();
265 root 1.1
266     if (res & 0x80)
267     {
268     int cnt = res & 0x7f;
269     res = 0;
270    
271     switch (cnt)
272     {
273     case 0:
274     error ("indefinite ASN.1 lengths not supported");
275     return 0;
276    
277     default:
278     error ("ASN.1 length too long");
279     return 0;
280    
281 root 1.2 case 4: res = (res << 8) | get_u8 ();
282     case 3: res = (res << 8) | get_u8 ();
283     case 2: res = (res << 8) | get_u8 ();
284     case 1: res = (res << 8) | get_u8 ();
285 root 1.1 }
286     }
287    
288     return res;
289     }
290    
291     static SV *
292 root 1.5 decode_int ()
293 root 1.1 {
294 root 1.5 int len = get_length ();
295 root 1.1
296 root 1.5 if (len <= 0)
297 root 1.1 {
298 root 1.5 error ("integer length equal to zero");
299 root 1.1 return 0;
300     }
301    
302 root 1.5 U8 *data = get_n (len);
303 root 1.1
304 root 1.5 int negative = data [0] & 0x80;
305 root 1.1
306 root 1.5 UV val = negative ? -1 : 0; // copy signbit to all bits
307 root 1.1
308 root 1.5 do
309     val = (val << 8) | *data++;
310     while (--len);
311 root 1.1
312 root 1.6 // the cast to IV relies on implementation-defined behaviour (two's complement cast)
313 root 1.5 // but that's ok, as perl relies on it as well.
314     return negative ? newSViv ((IV)val) : newSVuv (val);
315 root 1.1 }
316    
317     static SV *
318 root 1.5 decode_data (void)
319 root 1.1 {
320 root 1.5 U32 len = get_length ();
321     U8 *data = get_n (len);
322     return newSVpvn ((char *)data, len);
323 root 1.1 }
324    
325 root 1.2 // gelper for decode_object_identifier
326 root 1.1 static char *
327     write_uv (char *buf, U32 u)
328     {
329     // the one-digit case is absolutely predominant, so this pays off (hopefully)
330 root 1.5 if (expect_true (u < 10))
331 root 1.1 *buf++ = u + '0';
332     else
333     {
334     char *beg = buf;
335    
336     do
337     {
338     *buf++ = u % 10 + '0';
339     u /= 10;
340     }
341     while (u);
342    
343     // reverse digits
344     for (char *ptr = buf; --ptr != beg; ++beg)
345     {
346     char c = *ptr;
347     *ptr = *beg;
348     *beg = c;
349     }
350     }
351    
352     return buf;
353     }
354    
355     static SV *
356 root 1.5 decode_oid (int relative)
357 root 1.1 {
358 root 1.5 U32 len = get_length ();
359 root 1.1
360 root 1.5 if (len <= 0)
361 root 1.1 {
362     error ("OBJECT IDENTIFIER length equal to zero");
363     return &PL_sv_undef;
364     }
365    
366 root 1.5 U8 *end = cur + len;
367 root 1.3 U32 w = get_w ();
368 root 1.1
369     static char oid[MAX_OID_STRLEN]; // must be static
370     char *app = oid;
371    
372 root 1.5 if (relative)
373     app = write_uv (app, w);
374     else
375     {
376     app = write_uv (app, (U8)w / 40);
377     *app++ = '.';
378     app = write_uv (app, (U8)w % 40);
379     }
380 root 1.1
381     // we assume an oid component is never > 64 bytes
382     while (cur < end && oid + sizeof (oid) - app > 64)
383     {
384 root 1.3 w = get_w ();
385 root 1.1 *app++ = '.';
386     app = write_uv (app, w);
387     }
388    
389     return newSVpvn (oid, app - oid);
390     }
391    
392     static SV *
393 root 1.2 decode_ber ()
394 root 1.1 {
395 root 1.2 int identifier = get_u8 ();
396 root 1.1
397     SV *res;
398    
399 root 1.5 int constructed = identifier & ASN_CONSTRUCTED;
400     int klass = (identifier & ASN_CLASS_MASK) >> ASN_CLASS_SHIFT;
401     int tag = identifier & ASN_TAG_MASK;
402 root 1.1
403     if (tag == ASN_TAG_BER)
404 root 1.3 tag = get_w ();
405 root 1.1
406     if (tag == ASN_TAG_BER)
407 root 1.3 tag = get_w ();
408 root 1.1
409     if (constructed)
410     {
411 root 1.2 U32 len = get_length ();
412 root 1.1 U32 seqend = (cur - buf) + len;
413     AV *av = (AV *)sv_2mortal ((SV *)newAV ());
414    
415     while (cur < buf + seqend)
416 root 1.2 av_push (av, decode_ber ());
417 root 1.1
418     if (cur > buf + seqend)
419     croak ("constructed type %02x overflow (%x %x)\n", identifier, cur - buf, seqend);
420    
421     res = newRV_inc ((SV *)av);
422     }
423     else
424 root 1.5 switch (profile_lookup (cur_profile, klass, tag))
425 root 1.1 {
426 root 1.5 case BER_TYPE_NULL:
427 root 1.1 res = &PL_sv_undef;
428     break;
429    
430 root 1.5 case BER_TYPE_BOOL:
431     {
432     U32 len = get_length ();
433    
434     if (len != 1)
435 root 1.6 croak ("BER_TYPE_BOOLEAN type with invalid length %d encountered", len);
436 root 1.5
437     res = newSVcacheint (get_u8 () ? 0 : 1);
438     }
439     break;
440    
441     case BER_TYPE_OID:
442     res = decode_oid (0);
443 root 1.1 break;
444    
445 root 1.5 case BER_TYPE_RELOID:
446     res = decode_oid (1);
447 root 1.1 break;
448    
449 root 1.5 case BER_TYPE_INT:
450     res = decode_int ();
451 root 1.1 break;
452    
453 root 1.5 case BER_TYPE_UTF8:
454     res = decode_data ();
455     SvUTF8_on (res);
456 root 1.1 break;
457    
458 root 1.5 case BER_TYPE_BYTES:
459     res = decode_data ();
460 root 1.1 break;
461    
462 root 1.6 case BER_TYPE_IPADDRESS:
463     {
464     U32 len = get_length ();
465    
466     if (len != 4)
467     croak ("BER_TYPE_IPADDRESS type with invalid length %d encountered", len);
468    
469     U8 c1 = get_u8 ();
470     U8 c2 = get_u8 ();
471     U8 c3 = get_u8 ();
472     U8 c4 = get_u8 ();
473    
474     res = newSVpvf ("%d.%d.%d.%d", c1, c2, c3, c4);
475     }
476     break;
477    
478 root 1.5 case BER_TYPE_REAL:
479     case BER_TYPE_UCS2:
480     case BER_TYPE_UCS4:
481     case BER_TYPE_CROAK:
482 root 1.1 default:
483 root 1.5 croak ("unconfigured/unsupported class/tag %d/%d", klass, tag);
484 root 1.1 }
485    
486     AV *av = newAV ();
487     av_fill (av, BER_ARRAYSIZE - 1);
488 root 1.5 AvARRAY (av)[BER_CLASS ] = newSVcacheint (klass);
489 root 1.1 AvARRAY (av)[BER_TAG ] = newSVcacheint (tag);
490     AvARRAY (av)[BER_CONSTRUCTED] = newSVcacheint (constructed ? 1 : 0);
491     AvARRAY (av)[BER_DATA ] = res;
492    
493     return newRV_noinc ((SV *)av);
494     }
495    
496 root 1.3 /////////////////////////////////////////////////////////////////////////////
497     // encoder
498    
499     /* adds two STRLENs together, slow, and with paranoia */
500     static STRLEN
501     strlen_sum (STRLEN l1, STRLEN l2)
502     {
503     size_t sum = l1 + l2;
504    
505     if (sum < (size_t)l2 || sum != (size_t)(STRLEN)sum)
506     croak ("JSON::XS: string size overflow");
507    
508     return sum;
509     }
510    
511     static void
512     set_buf (SV *sv)
513     {
514     STRLEN len;
515     buf_sv = sv;
516     buf = SvPVbyte (buf_sv, len);
517     cur = buf;
518     end = buf + len;
519     }
520    
521     /* similar to SvGROW, but somewhat safer and guarantees exponential realloc strategy */
522     static char *
523     my_sv_grow (SV *sv, size_t len1, size_t len2)
524     {
525     len1 = strlen_sum (len1, len2);
526     len1 = strlen_sum (len1, len1 >> 1);
527    
528     if (len1 > 4096 - 24)
529     len1 = (len1 | 4095) - 24;
530    
531     return SvGROW (sv, len1);
532     }
533    
534     static void
535     need (STRLEN len)
536     {
537     if (expect_false ((uintptr_t)(end - cur) < len))
538     {
539     STRLEN pos = cur - buf;
540     buf = my_sv_grow (buf_sv, pos, len);
541     cur = buf + pos;
542     end = buf + SvLEN (buf_sv) - 1;
543     }
544     }
545    
546     static void
547     put_u8 (int val)
548     {
549     need (1);
550     *cur++ = val;
551     }
552    
553     static void
554     put_w_nocheck (U32 val)
555     {
556     *cur = (val >> 7 * 4) | 0x80; cur += val >= (1 << (7 * 4));
557     *cur = (val >> 7 * 3) | 0x80; cur += val >= (1 << (7 * 3));
558     *cur = (val >> 7 * 2) | 0x80; cur += val >= (1 << (7 * 2));
559     *cur = (val >> 7 * 1) | 0x80; cur += val >= (1 << (7 * 1));
560     *cur = val & 0x7f; cur += 1;
561     }
562    
563     static void
564     put_w (U32 val)
565     {
566     need (5); // we only handle up to 5 bytes
567    
568     put_w_nocheck (val);
569     }
570    
571     static U8 *
572     put_length_at (U32 val, U8 *cur)
573     {
574     if (val < 0x7fU)
575     *cur++ = val;
576     else
577     {
578     U8 *lenb = cur++;
579    
580     *cur = val >> 24; cur += *cur > 0;
581     *cur = val >> 16; cur += *cur > 0;
582     *cur = val >> 8; cur += *cur > 0;
583     *cur = val ; cur += 1;
584    
585     *lenb = 0x80 + cur - lenb - 1;
586     }
587    
588     return cur;
589     }
590    
591     static void
592     put_length (U32 val)
593     {
594     need (5);
595     cur = put_length_at (val, cur);
596     }
597    
598     // return how many bytes the encoded length requires
599     static int length_length (U32 val)
600     {
601     return val < 0x7fU
602     ? 1
603     : 2 + (val > 0xffU) + (val > 0xffffU) + (val > 0xffffffU);
604     }
605    
606     static void
607 root 1.5 encode_data (const char *ptr, STRLEN len)
608 root 1.3 {
609     put_length (len);
610     need (len);
611     memcpy (cur, ptr, len);
612     cur += len;
613     }
614    
615     static void
616 root 1.5 encode_uv (UV uv)
617     {
618     }
619    
620     static void
621     encode_int (SV *sv)
622 root 1.3 {
623 root 1.5 need (8 + 1 + 1); // 64 bit + length + extra 0
624    
625     if (expect_false (!SvIOK (sv)))
626     sv_2iv_flags (sv, 0);
627 root 1.3
628     U8 *lenb = cur++;
629    
630 root 1.5 if (SvIOK_notUV (sv))
631 root 1.3 {
632 root 1.5 IV iv = SvIVX (sv);
633    
634     if (expect_false (iv < 0))
635     {
636     // get two's complement bit pattern - works even on hypothetical non-2c machines
637     UV uv = iv;
638    
639     #if UVSIZE > 4
640     *cur = uv >> 56; cur += !!(~uv & 0xff80000000000000U);
641     *cur = uv >> 48; cur += !!(~uv & 0xffff800000000000U);
642     *cur = uv >> 40; cur += !!(~uv & 0xffffff8000000000U);
643     *cur = uv >> 32; cur += !!(~uv & 0xffffffff80000000U);
644     #endif
645     *cur = uv >> 24; cur += !!(~uv & 0xffffffffff800000U);
646     *cur = uv >> 16; cur += !!(~uv & 0xffffffffffff8000U);
647     *cur = uv >> 8; cur += !!(~uv & 0xffffffffffffff80U);
648     *cur = uv ; cur += 1;
649    
650     *lenb = cur - lenb - 1;
651 root 1.3
652 root 1.5 return;
653     }
654 root 1.3 }
655    
656 root 1.5 UV uv = SvUV (sv);
657 root 1.3
658 root 1.5 // prepend an extra 0 if the high bit is 1
659     *cur = 0; cur += !!(uv & ((UV)1 << (UVSIZE * 8 - 1)));
660 root 1.3
661 root 1.5 #if UVSIZE > 4
662     *cur = uv >> 56; cur += !!(uv & 0xff80000000000000U);
663     *cur = uv >> 48; cur += !!(uv & 0xffff800000000000U);
664     *cur = uv >> 40; cur += !!(uv & 0xffffff8000000000U);
665     *cur = uv >> 32; cur += !!(uv & 0xffffffff80000000U);
666     #endif
667     *cur = uv >> 24; cur += !!(uv & 0xffffffffff800000U);
668     *cur = uv >> 16; cur += !!(uv & 0xffffffffffff8000U);
669     *cur = uv >> 8; cur += !!(uv & 0xffffffffffffff80U);
670 root 1.3 *cur = uv ; cur += 1;
671    
672     *lenb = cur - lenb - 1;
673     }
674    
675     // we don't know the length yet, so we optimistically
676     // assume the length will need one octet later. if that
677     // turns out to be wrong, we memove as needed.
678     // mark the beginning
679     static STRLEN
680     len_fixup_mark ()
681     {
682     return cur++ - buf;
683     }
684    
685     // patch up the length
686     static void
687     len_fixup (STRLEN mark)
688     {
689     STRLEN reallen = (cur - buf) - mark - 1;
690     int lenlen = length_length (reallen);
691    
692     if (expect_false (lenlen > 1))
693     {
694     // bad luck, we have to shift the bytes to make room for the length
695     need (5);
696     memmove (buf + mark + lenlen, buf + mark + 1, reallen);
697     cur += lenlen - 1;
698     }
699    
700     put_length_at (reallen, buf + mark);
701     }
702    
703     static char *
704     read_uv (char *str, UV *uv)
705     {
706     UV r = 0;
707    
708     while (*str >= '0')
709     r = r * 10 + *str++ - '0';
710    
711     *uv = r;
712    
713     str += !!*str; // advance over any non-zero byte
714    
715     return str;
716     }
717    
718     static void
719 root 1.5 encode_oid (SV *oid, int relative)
720 root 1.3 {
721 root 1.5 STRLEN len;
722     char *ptr = SvPV (oid, len); // utf8 vs. bytes does not matter
723 root 1.3
724     // we need at most as many octets as the string form
725 root 1.5 need (len + 1);
726 root 1.3 STRLEN mark = len_fixup_mark ();
727    
728     UV w1, w2;
729    
730 root 1.5 if (!relative)
731     {
732     ptr = read_uv (ptr, &w1);
733     ptr = read_uv (ptr, &w2);
734 root 1.3
735 root 1.5 put_w_nocheck (w1 * 40 + w2);
736     }
737 root 1.3
738     while (*ptr)
739     {
740     ptr = read_uv (ptr, &w1);
741     put_w_nocheck (w1);
742     }
743    
744     len_fixup (mark);
745     }
746    
747 root 1.5 // check whether an SV is a BER tuple and returns its AV *
748 root 1.4 static AV *
749     ber_tuple (SV *tuple)
750 root 1.3 {
751 root 1.4 SV *rv;
752    
753     if (expect_false (!SvROK (tuple) || SvTYPE ((rv = SvRV (tuple))) != SVt_PVAV))
754 root 1.3 croak ("BER tuple must be array-reference");
755    
756 root 1.4 if (expect_false (SvRMAGICAL (rv)))
757     croak ("BER tuple must not be tied");
758 root 1.3
759 root 1.4 if (expect_false (AvFILL ((AV *)rv) != BER_ARRAYSIZE - 1))
760     croak ("BER tuple must contain exactly %d elements, not %d", BER_ARRAYSIZE, AvFILL ((AV *)rv) + 1);
761 root 1.3
762 root 1.4 return (AV *)rv;
763     }
764    
765     static void
766     encode_ber (SV *tuple)
767     {
768     AV *av = ber_tuple (tuple);
769 root 1.3
770     int klass = SvIV (AvARRAY (av)[BER_CLASS]);
771     int tag = SvIV (AvARRAY (av)[BER_TAG]);
772     int constructed = SvIV (AvARRAY (av)[BER_CONSTRUCTED]) ? ASN_CONSTRUCTED : 0;
773     SV *data = AvARRAY (av)[BER_DATA];
774    
775     int identifier = (klass << ASN_CLASS_SHIFT) | constructed;
776    
777     if (expect_false (tag >= ASN_TAG_BER))
778     {
779     put_u8 (identifier | ASN_TAG_BER);
780     put_w (tag);
781     }
782     else
783     put_u8 (identifier | tag);
784    
785     if (constructed)
786     {
787     // we optimistically assume that only one length byte is needed
788     // and adjust later
789     need (1);
790     STRLEN mark = len_fixup_mark ();
791    
792     if (expect_false (!SvROK (data) || SvTYPE (SvRV (data)) != SVt_PVAV))
793     croak ("BER constructed data must be array-reference");
794    
795     AV *av = (AV *)SvRV (data);
796     int fill = AvFILL (av);
797    
798     if (expect_false (SvRMAGICAL (av)))
799     croak ("BER constructed data must not be tied");
800    
801     for (int i = 0; i <= fill; ++i)
802     encode_ber (AvARRAY (av)[i]);
803    
804     len_fixup (mark);
805     }
806     else
807 root 1.5 switch (profile_lookup (cur_profile, klass, tag))
808 root 1.3 {
809 root 1.5 case BER_TYPE_NULL:
810 root 1.3 put_length (0);
811     break;
812    
813 root 1.5 case BER_TYPE_BOOL:
814     put_length (1);
815     put_u8 (SvTRUE (data) ? 0xff : 0x00);
816 root 1.3 break;
817    
818 root 1.5 case BER_TYPE_OID:
819     encode_oid (data, 0);
820 root 1.3 break;
821    
822 root 1.5 case BER_TYPE_RELOID:
823     encode_oid (data, 1);
824 root 1.3 break;
825    
826 root 1.5 case BER_TYPE_INT:
827     encode_int (data);
828     break;
829    
830     case BER_TYPE_BYTES:
831     {
832     STRLEN len;
833     const char *ptr = SvPVbyte (data, len);
834     encode_data (ptr, len);
835     }
836     break;
837    
838     case BER_TYPE_UTF8:
839     {
840     STRLEN len;
841     const char *ptr = SvPVutf8 (data, len);
842     encode_data (ptr, len);
843     }
844     break;
845    
846 root 1.6 case BER_TYPE_IPADDRESS:
847     {
848     U8 ip[4];
849     sscanf (SvPV_nolen (data), "%hhu.%hhu.%hhu.%hhu", ip + 0, ip + 1, ip + 2, ip + 3);
850     encode_data ((const char *)ip, sizeof (ip));
851     }
852     break;
853    
854 root 1.5 case BER_TYPE_REAL:
855     case BER_TYPE_UCS2:
856     case BER_TYPE_UCS4:
857     case BER_TYPE_CROAK:
858 root 1.3 default:
859 root 1.5 croak ("unconfigured/unsupported class/tag %d/%d", klass, tag);
860 root 1.3 }
861    
862     }
863    
864     /////////////////////////////////////////////////////////////////////////////
865    
866 root 1.1 MODULE = Convert::BER::XS PACKAGE = Convert::BER::XS
867    
868     PROTOTYPES: ENABLE
869    
870     BOOT:
871     {
872     HV *stash = gv_stashpv ("Convert::BER::XS", 1);
873    
874 root 1.5 profile_stash = gv_stashpv ("Convert::BER::XS::Profile", 1);
875    
876 root 1.1 static const struct {
877     const char *name;
878     IV iv;
879     } *civ, const_iv[] = {
880 root 1.5 #define const_iv(name) { # name, name },
881     const_iv (ASN_BOOLEAN)
882     const_iv (ASN_INTEGER32)
883     const_iv (ASN_BIT_STRING)
884     const_iv (ASN_OCTET_STRING)
885     const_iv (ASN_NULL)
886     const_iv (ASN_OBJECT_IDENTIFIER)
887     const_iv (ASN_OBJECT_DESCRIPTOR)
888     const_iv (ASN_OID)
889     const_iv (ASN_EXTERNAL)
890     const_iv (ASN_REAL)
891     const_iv (ASN_SEQUENCE)
892     const_iv (ASN_ENUMERATED)
893     const_iv (ASN_EMBEDDED_PDV)
894     const_iv (ASN_UTF8_STRING)
895     const_iv (ASN_RELATIVE_OID)
896     const_iv (ASN_SET)
897     const_iv (ASN_NUMERIC_STRING)
898     const_iv (ASN_PRINTABLE_STRING)
899     const_iv (ASN_TELETEX_STRING)
900     const_iv (ASN_T61_STRING)
901     const_iv (ASN_VIDEOTEX_STRING)
902     const_iv (ASN_IA5_STRING)
903     const_iv (ASN_ASCII_STRING)
904     const_iv (ASN_UTC_TIME)
905     const_iv (ASN_GENERALIZED_TIME)
906     const_iv (ASN_GRAPHIC_STRING)
907     const_iv (ASN_VISIBLE_STRING)
908     const_iv (ASN_ISO646_STRING)
909     const_iv (ASN_GENERAL_STRING)
910     const_iv (ASN_UNIVERSAL_STRING)
911     const_iv (ASN_CHARACTER_STRING)
912     const_iv (ASN_BMP_STRING)
913    
914     const_iv (ASN_UNIVERSAL)
915     const_iv (ASN_APPLICATION)
916     const_iv (ASN_CONTEXT)
917     const_iv (ASN_PRIVATE)
918    
919     const_iv (BER_CLASS)
920     const_iv (BER_TAG)
921     const_iv (BER_CONSTRUCTED)
922     const_iv (BER_DATA)
923    
924     const_iv (BER_TYPE_BYTES)
925     const_iv (BER_TYPE_UTF8)
926     const_iv (BER_TYPE_UCS2)
927     const_iv (BER_TYPE_UCS4)
928     const_iv (BER_TYPE_INT)
929     const_iv (BER_TYPE_OID)
930     const_iv (BER_TYPE_RELOID)
931     const_iv (BER_TYPE_NULL)
932     const_iv (BER_TYPE_BOOL)
933     const_iv (BER_TYPE_REAL)
934 root 1.6 const_iv (BER_TYPE_IPADDRESS)
935 root 1.5 const_iv (BER_TYPE_CROAK)
936    
937     const_iv (SNMP_IPADDRESS)
938     const_iv (SNMP_COUNTER32)
939     const_iv (SNMP_UNSIGNED32)
940     const_iv (SNMP_TIMETICKS)
941     const_iv (SNMP_OPAQUE)
942     const_iv (SNMP_COUNTER64)
943 root 1.1 };
944    
945     for (civ = const_iv + sizeof (const_iv) / sizeof (const_iv [0]); civ > const_iv; civ--)
946     newCONSTSUB (stash, (char *)civ[-1].name, newSViv (civ[-1].iv));
947     }
948    
949     SV *
950 root 1.5 ber_decode (SV *ber, SV *profile = &PL_sv_undef)
951 root 1.1 CODE:
952     {
953 root 1.5 cur_profile = SvPROFILE (profile);
954 root 1.3 STRLEN len;
955 root 1.1 buf = SvPVbyte (ber, len);
956     cur = buf;
957 root 1.3 end = buf + len;
958 root 1.1
959 root 1.2 RETVAL = decode_ber ();
960 root 1.1 }
961     OUTPUT: RETVAL
962    
963     void
964     ber_is (SV *tuple, SV *klass = &PL_sv_undef, SV *tag = &PL_sv_undef, SV *constructed = &PL_sv_undef, SV *data = &PL_sv_undef)
965     PPCODE:
966     {
967     if (!SvOK (tuple))
968     XSRETURN_NO;
969    
970     if (!SvROK (tuple) || SvTYPE (SvRV (tuple)) != SVt_PVAV)
971 root 1.4 croak ("ber_is: tuple must be BER tuple (array-ref)");
972 root 1.1
973     AV *av = (AV *)SvRV (tuple);
974    
975     XPUSHs (
976     (!SvOK (klass) || SvIV (AvARRAY (av)[BER_CLASS ]) == SvIV (klass))
977     && (!SvOK (tag) || SvIV (AvARRAY (av)[BER_TAG ]) == SvIV (tag))
978     && (!SvOK (constructed) || !SvIV (AvARRAY (av)[BER_CONSTRUCTED]) == !SvIV (constructed))
979     && (!SvOK (data) || sv_eq (AvARRAY (av)[BER_DATA ], data))
980 root 1.4 ? &PL_sv_yes : &PL_sv_undef);
981 root 1.1 }
982    
983     void
984     ber_is_seq (SV *tuple)
985     PPCODE:
986     {
987     if (!SvOK (tuple))
988     XSRETURN_UNDEF;
989    
990 root 1.4 AV *av = ber_tuple (tuple);
991 root 1.1
992     XPUSHs (
993     SvIV (AvARRAY (av)[BER_CLASS ]) == ASN_UNIVERSAL
994     && SvIV (AvARRAY (av)[BER_TAG ]) == ASN_SEQUENCE
995     && SvIV (AvARRAY (av)[BER_CONSTRUCTED])
996     ? AvARRAY (av)[BER_DATA] : &PL_sv_undef);
997     }
998    
999     void
1000 root 1.4 ber_is_i32 (SV *tuple, SV *value = &PL_sv_undef)
1001 root 1.1 PPCODE:
1002     {
1003     if (!SvOK (tuple))
1004     XSRETURN_NO;
1005    
1006 root 1.4 AV *av = ber_tuple (tuple);
1007 root 1.1
1008 root 1.4 IV data = SvIV (AvARRAY (av)[BER_DATA]);
1009 root 1.1
1010     XPUSHs (
1011 root 1.4 SvIV (AvARRAY (av)[BER_CLASS ]) == ASN_UNIVERSAL
1012     && SvIV (AvARRAY (av)[BER_TAG ]) == ASN_INTEGER32
1013     && !SvIV (AvARRAY (av)[BER_CONSTRUCTED])
1014     && (!SvOK (value) || data == SvIV (value))
1015     ? sv_2mortal (data ? newSViv (data) : newSVpv ("0 but true", 0))
1016     : &PL_sv_undef);
1017 root 1.1 }
1018    
1019     void
1020 root 1.4 ber_is_oid (SV *tuple, SV *oid = &PL_sv_undef)
1021 root 1.1 PPCODE:
1022     {
1023     if (!SvOK (tuple))
1024     XSRETURN_NO;
1025    
1026 root 1.4 AV *av = ber_tuple (tuple);
1027 root 1.1
1028     XPUSHs (
1029     SvIV (AvARRAY (av)[BER_CLASS ]) == ASN_UNIVERSAL
1030     && SvIV (AvARRAY (av)[BER_TAG ]) == ASN_OBJECT_IDENTIFIER
1031     && !SvIV (AvARRAY (av)[BER_CONSTRUCTED])
1032 root 1.4 && (!SvOK (oid) || sv_eq (AvARRAY (av)[BER_DATA], oid))
1033     ? newSVsv (AvARRAY (av)[BER_DATA]) : &PL_sv_undef);
1034 root 1.1 }
1035    
1036 root 1.3 #############################################################################
1037    
1038     void
1039 root 1.5 ber_encode (SV *tuple, SV *profile = &PL_sv_undef)
1040 root 1.3 PPCODE:
1041     {
1042 root 1.5 cur_profile = SvPROFILE (profile);
1043 root 1.3 buf_sv = sv_2mortal (NEWSV (0, 256));
1044     SvPOK_only (buf_sv);
1045     set_buf (buf_sv);
1046    
1047     encode_ber (tuple);
1048    
1049     SvCUR_set (buf_sv, cur - buf);
1050     XPUSHs (buf_sv);
1051     }
1052    
1053 root 1.4 SV *
1054     ber_i32 (IV iv)
1055     CODE:
1056     {
1057     AV *av = newAV ();
1058     av_fill (av, BER_ARRAYSIZE - 1);
1059     AvARRAY (av)[BER_CLASS ] = newSVcacheint (ASN_UNIVERSAL);
1060     AvARRAY (av)[BER_TAG ] = newSVcacheint (ASN_INTEGER32);
1061     AvARRAY (av)[BER_CONSTRUCTED] = newSVcacheint (0);
1062     AvARRAY (av)[BER_DATA ] = newSViv (iv);
1063     RETVAL = newRV_noinc ((SV *)av);
1064     }
1065     OUTPUT: RETVAL
1066    
1067     # TODO: not arrayref, but elements?
1068     SV *
1069     ber_seq (SV *arrayref)
1070     CODE:
1071     {
1072     AV *av = newAV ();
1073     av_fill (av, BER_ARRAYSIZE - 1);
1074     AvARRAY (av)[BER_CLASS ] = newSVcacheint (ASN_UNIVERSAL);
1075     AvARRAY (av)[BER_TAG ] = newSVcacheint (ASN_SEQUENCE);
1076     AvARRAY (av)[BER_CONSTRUCTED] = newSVcacheint (1);
1077     AvARRAY (av)[BER_DATA ] = newSVsv (arrayref);
1078     RETVAL = newRV_noinc ((SV *)av);
1079     }
1080     OUTPUT: RETVAL
1081    
1082 root 1.5 MODULE = Convert::BER::XS PACKAGE = Convert::BER::XS::Profile
1083    
1084     SV *
1085     new (SV *klass)
1086     CODE:
1087     RETVAL = profile_new ();
1088     OUTPUT: RETVAL
1089    
1090 root 1.6 void
1091     set (SV *profile, int klass, int tag, int type)
1092     CODE:
1093     profile_set (SvPROFILE (profile), klass, tag, type);
1094    
1095     IV
1096     get (SV *profile, int klass, int tag)
1097     CODE:
1098     RETVAL = profile_lookup (SvPROFILE (profile), klass, tag);
1099     OUTPUT: RETVAL
1100    
1101     void
1102     _set_default (SV *profile)
1103     CODE:
1104     default_profile = SvPROFILE (profile);
1105    
1106