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