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

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

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines