Use a compiler to marshall/unmarshall the sessions
[mod_auth_gssapi.git] / src / asn1c / INTEGER.c
1 /*-
2  * Copyright (c) 2003-2014 Lev Walkin <vlm@lionet.info>.
3  * All rights reserved.
4  * Redistribution and modifications are permitted subject to BSD license.
5  */
6 #include <asn_internal.h>
7 #include <INTEGER.h>
8 #include <asn_codecs_prim.h>    /* Encoder and decoder of a primitive type */
9 #include <errno.h>
10
11 /*
12  * INTEGER basic type description.
13  */
14 static ber_tlv_tag_t asn_DEF_INTEGER_tags[] = {
15         (ASN_TAG_CLASS_UNIVERSAL | (2 << 2))
16 };
17 asn_TYPE_descriptor_t asn_DEF_INTEGER = {
18         "INTEGER",
19         "INTEGER",
20         ASN__PRIMITIVE_TYPE_free,
21         INTEGER_print,
22         asn_generic_no_constraint,
23         ber_decode_primitive,
24         INTEGER_encode_der,
25         INTEGER_decode_xer,
26         INTEGER_encode_xer,
27 #ifdef  ASN_DISABLE_PER_SUPPORT
28         0,
29         0,
30 #else
31         INTEGER_decode_uper,    /* Unaligned PER decoder */
32         INTEGER_encode_uper,    /* Unaligned PER encoder */
33 #endif  /* ASN_DISABLE_PER_SUPPORT */
34         0, /* Use generic outmost tag fetcher */
35         asn_DEF_INTEGER_tags,
36         sizeof(asn_DEF_INTEGER_tags) / sizeof(asn_DEF_INTEGER_tags[0]),
37         asn_DEF_INTEGER_tags,   /* Same as above */
38         sizeof(asn_DEF_INTEGER_tags) / sizeof(asn_DEF_INTEGER_tags[0]),
39         0,      /* No PER visible constraints */
40         0, 0,   /* No members */
41         0       /* No specifics */
42 };
43
44 /*
45  * Encode INTEGER type using DER.
46  */
47 asn_enc_rval_t
48 INTEGER_encode_der(asn_TYPE_descriptor_t *td, void *sptr,
49         int tag_mode, ber_tlv_tag_t tag,
50         asn_app_consume_bytes_f *cb, void *app_key) {
51         INTEGER_t *st = (INTEGER_t *)sptr;
52
53         ASN_DEBUG("%s %s as INTEGER (tm=%d)",
54                 cb?"Encoding":"Estimating", td->name, tag_mode);
55
56         /*
57          * Canonicalize integer in the buffer.
58          * (Remove too long sign extension, remove some first 0x00 bytes)
59          */
60         if(st->buf) {
61                 uint8_t *buf = st->buf;
62                 uint8_t *end1 = buf + st->size - 1;
63                 int shift;
64
65                 /* Compute the number of superfluous leading bytes */
66                 for(; buf < end1; buf++) {
67                         /*
68                          * If the contents octets of an integer value encoding
69                          * consist of more than one octet, then the bits of the
70                          * first octet and bit 8 of the second octet:
71                          * a) shall not all be ones; and
72                          * b) shall not all be zero.
73                          */
74                         switch(*buf) {
75                         case 0x00: if((buf[1] & 0x80) == 0)
76                                         continue;
77                                 break;
78                         case 0xff: if((buf[1] & 0x80))
79                                         continue;
80                                 break;
81                         }
82                         break;
83                 }
84
85                 /* Remove leading superfluous bytes from the integer */
86                 shift = buf - st->buf;
87                 if(shift) {
88                         uint8_t *nb = st->buf;
89                         uint8_t *end;
90
91                         st->size -= shift;      /* New size, minus bad bytes */
92                         end = nb + st->size;
93
94                         for(; nb < end; nb++, buf++)
95                                 *nb = *buf;
96                 }
97
98         } /* if(1) */
99
100         return der_encode_primitive(td, sptr, tag_mode, tag, cb, app_key);
101 }
102
103 static const asn_INTEGER_enum_map_t *INTEGER_map_enum2value(asn_INTEGER_specifics_t *specs, const char *lstart, const char *lstop);
104
105 /*
106  * INTEGER specific human-readable output.
107  */
108 static ssize_t
109 INTEGER__dump(asn_TYPE_descriptor_t *td, const INTEGER_t *st, asn_app_consume_bytes_f *cb, void *app_key, int plainOrXER) {
110         asn_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics;
111         char scratch[32];       /* Enough for 64-bit integer */
112         uint8_t *buf = st->buf;
113         uint8_t *buf_end = st->buf + st->size;
114         signed long value;
115         ssize_t wrote = 0;
116         char *p;
117         int ret;
118
119         if(specs && specs->field_unsigned)
120                 ret = asn_INTEGER2ulong(st, (unsigned long *)&value);
121         else
122                 ret = asn_INTEGER2long(st, &value);
123
124         /* Simple case: the integer size is small */
125         if(ret == 0) {
126                 const asn_INTEGER_enum_map_t *el;
127                 size_t scrsize;
128                 char *scr;
129
130                 el = (value >= 0 || !specs || !specs->field_unsigned)
131                         ? INTEGER_map_value2enum(specs, value) : 0;
132                 if(el) {
133                         scrsize = el->enum_len + 32;
134                         scr = (char *)alloca(scrsize);
135                         if(plainOrXER == 0)
136                                 ret = snprintf(scr, scrsize,
137                                         "%ld (%s)", value, el->enum_name);
138                         else
139                                 ret = snprintf(scr, scrsize,
140                                         "<%s/>", el->enum_name);
141                 } else if(plainOrXER && specs && specs->strict_enumeration) {
142                         ASN_DEBUG("ASN.1 forbids dealing with "
143                                 "unknown value of ENUMERATED type");
144                         errno = EPERM;
145                         return -1;
146                 } else {
147                         scrsize = sizeof(scratch);
148                         scr = scratch;
149                         ret = snprintf(scr, scrsize,
150                                 (specs && specs->field_unsigned)
151                                 ?"%lu":"%ld", value);
152                 }
153                 assert(ret > 0 && (size_t)ret < scrsize);
154                 return (cb(scr, ret, app_key) < 0) ? -1 : ret;
155         } else if(plainOrXER && specs && specs->strict_enumeration) {
156                 /*
157                  * Here and earlier, we cannot encode the ENUMERATED values
158                  * if there is no corresponding identifier.
159                  */
160                 ASN_DEBUG("ASN.1 forbids dealing with "
161                         "unknown value of ENUMERATED type");
162                 errno = EPERM;
163                 return -1;
164         }
165
166         /* Output in the long xx:yy:zz... format */
167         /* TODO: replace with generic algorithm (Knuth TAOCP Vol 2, 4.3.1) */
168         for(p = scratch; buf < buf_end; buf++) {
169                 static const char *h2c = "0123456789ABCDEF";
170                 if((p - scratch) >= (ssize_t)(sizeof(scratch) - 4)) {
171                         /* Flush buffer */
172                         if(cb(scratch, p - scratch, app_key) < 0)
173                                 return -1;
174                         wrote += p - scratch;
175                         p = scratch;
176                 }
177                 *p++ = h2c[*buf >> 4];
178                 *p++ = h2c[*buf & 0x0F];
179                 *p++ = 0x3a;    /* ":" */
180         }
181         if(p != scratch)
182                 p--;    /* Remove the last ":" */
183
184         wrote += p - scratch;
185         return (cb(scratch, p - scratch, app_key) < 0) ? -1 : wrote;
186 }
187
188 /*
189  * INTEGER specific human-readable output.
190  */
191 int
192 INTEGER_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel,
193         asn_app_consume_bytes_f *cb, void *app_key) {
194         const INTEGER_t *st = (const INTEGER_t *)sptr;
195         ssize_t ret;
196
197         (void)td;
198         (void)ilevel;
199
200         if(!st || !st->buf)
201                 ret = cb("<absent>", 8, app_key);
202         else
203                 ret = INTEGER__dump(td, st, cb, app_key, 0);
204
205         return (ret < 0) ? -1 : 0;
206 }
207
208 struct e2v_key {
209         const char *start;
210         const char *stop;
211         asn_INTEGER_enum_map_t *vemap;
212         unsigned int *evmap;
213 };
214 static int
215 INTEGER__compar_enum2value(const void *kp, const void *am) {
216         const struct e2v_key *key = (const struct e2v_key *)kp;
217         const asn_INTEGER_enum_map_t *el = (const asn_INTEGER_enum_map_t *)am;
218         const char *ptr, *end, *name;
219
220         /* Remap the element (sort by different criterion) */
221         el = key->vemap + key->evmap[el - key->vemap];
222
223         /* Compare strings */
224         for(ptr = key->start, end = key->stop, name = el->enum_name;
225                         ptr < end; ptr++, name++) {
226                 if(*ptr != *name)
227                         return *(const unsigned char *)ptr
228                                 - *(const unsigned char *)name;
229         }
230         return name[0] ? -1 : 0;
231 }
232
233 static const asn_INTEGER_enum_map_t *
234 INTEGER_map_enum2value(asn_INTEGER_specifics_t *specs, const char *lstart, const char *lstop) {
235         asn_INTEGER_enum_map_t *el_found;
236         int count = specs ? specs->map_count : 0;
237         struct e2v_key key;
238         const char *lp;
239
240         if(!count) return NULL;
241
242         /* Guaranteed: assert(lstart < lstop); */
243         /* Figure out the tag name */
244         for(lstart++, lp = lstart; lp < lstop; lp++) {
245                 switch(*lp) {
246                 case 9: case 10: case 11: case 12: case 13: case 32: /* WSP */
247                 case 0x2f: /* '/' */ case 0x3e: /* '>' */
248                         break;
249                 default:
250                         continue;
251                 }
252                 break;
253         }
254         if(lp == lstop) return NULL;    /* No tag found */
255         lstop = lp;
256
257         key.start = lstart;
258         key.stop = lstop;
259         key.vemap = specs->value2enum;
260         key.evmap = specs->enum2value;
261         el_found = (asn_INTEGER_enum_map_t *)bsearch(&key,
262                 specs->value2enum, count, sizeof(specs->value2enum[0]),
263                 INTEGER__compar_enum2value);
264         if(el_found) {
265                 /* Remap enum2value into value2enum */
266                 el_found = key.vemap + key.evmap[el_found - key.vemap];
267         }
268         return el_found;
269 }
270
271 static int
272 INTEGER__compar_value2enum(const void *kp, const void *am) {
273         long a = *(const long *)kp;
274         const asn_INTEGER_enum_map_t *el = (const asn_INTEGER_enum_map_t *)am;
275         long b = el->nat_value;
276         if(a < b) return -1;
277         else if(a == b) return 0;
278         else return 1;
279 }
280
281 const asn_INTEGER_enum_map_t *
282 INTEGER_map_value2enum(asn_INTEGER_specifics_t *specs, long value) {
283         int count = specs ? specs->map_count : 0;
284         if(!count) return 0;
285         return (asn_INTEGER_enum_map_t *)bsearch(&value, specs->value2enum,
286                 count, sizeof(specs->value2enum[0]),
287                 INTEGER__compar_value2enum);
288 }
289
290 static int
291 INTEGER_st_prealloc(INTEGER_t *st, int min_size) {
292         void *p = MALLOC(min_size + 1);
293         if(p) {
294                 void *b = st->buf;
295                 st->size = 0;
296                 st->buf = p;
297                 FREEMEM(b);
298                 return 0;
299         } else {
300                 return -1;
301         }
302 }
303
304 /*
305  * Decode the chunk of XML text encoding INTEGER.
306  */
307 static enum xer_pbd_rval
308 INTEGER__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, const void *chunk_buf, size_t chunk_size) {
309         INTEGER_t *st = (INTEGER_t *)sptr;
310         long dec_value;
311         long hex_value = 0;
312         const char *lp;
313         const char *lstart = (const char *)chunk_buf;
314         const char *lstop = lstart + chunk_size;
315         enum {
316                 ST_LEADSPACE,
317                 ST_SKIPSPHEX,
318                 ST_WAITDIGITS,
319                 ST_DIGITS,
320                 ST_DIGITS_TRAILSPACE,
321                 ST_HEXDIGIT1,
322                 ST_HEXDIGIT2,
323                 ST_HEXDIGITS_TRAILSPACE,
324                 ST_HEXCOLON,
325                 ST_END_ENUM,
326                 ST_UNEXPECTED
327         } state = ST_LEADSPACE;
328         const char *dec_value_start = 0; /* INVARIANT: always !0 in ST_DIGITS */
329         const char *dec_value_end = 0;
330
331         if(chunk_size)
332                 ASN_DEBUG("INTEGER body %ld 0x%2x..0x%2x",
333                         (long)chunk_size, *lstart, lstop[-1]);
334
335         if(INTEGER_st_prealloc(st, (chunk_size/3) + 1))
336                 return XPBD_SYSTEM_FAILURE;
337
338         /*
339          * We may have received a tag here. It will be processed inline.
340          * Use strtoul()-like code and serialize the result.
341          */
342         for(lp = lstart; lp < lstop; lp++) {
343                 int lv = *lp;
344                 switch(lv) {
345                 case 0x09: case 0x0a: case 0x0d: case 0x20:
346                         switch(state) {
347                         case ST_LEADSPACE:
348                         case ST_DIGITS_TRAILSPACE:
349                         case ST_HEXDIGITS_TRAILSPACE:
350                         case ST_SKIPSPHEX:
351                                 continue;
352                         case ST_DIGITS:
353                                 dec_value_end = lp;
354                                 state = ST_DIGITS_TRAILSPACE;
355                                 continue;
356                         case ST_HEXCOLON:
357                                 state = ST_HEXDIGITS_TRAILSPACE;
358                                 continue;
359                         default:
360                                 break;
361                         }
362                         break;
363                 case 0x2d:      /* '-' */
364                         if(state == ST_LEADSPACE) {
365                                 dec_value = 0;
366                                 dec_value_start = lp;
367                                 state = ST_WAITDIGITS;
368                                 continue;
369                         }
370                         break;
371                 case 0x2b:      /* '+' */
372                         if(state == ST_LEADSPACE) {
373                                 dec_value = 0;
374                                 dec_value_start = lp;
375                                 state = ST_WAITDIGITS;
376                                 continue;
377                         }
378                         break;
379                 case 0x30: case 0x31: case 0x32: case 0x33: case 0x34:
380                 case 0x35: case 0x36: case 0x37: case 0x38: case 0x39:
381                         switch(state) {
382                         case ST_DIGITS: continue;
383                         case ST_SKIPSPHEX:      /* Fall through */
384                         case ST_HEXDIGIT1:
385                                 hex_value = (lv - 0x30) << 4;
386                                 state = ST_HEXDIGIT2;
387                                 continue;
388                         case ST_HEXDIGIT2:
389                                 hex_value += (lv - 0x30);
390                                 state = ST_HEXCOLON;
391                                 st->buf[st->size++] = (uint8_t)hex_value;
392                                 continue;
393                         case ST_HEXCOLON:
394                                 return XPBD_BROKEN_ENCODING;
395                         case ST_LEADSPACE:
396                                 dec_value = 0;
397                                 dec_value_start = lp;
398                                 /* FALL THROUGH */
399                         case ST_WAITDIGITS:
400                                 state = ST_DIGITS;
401                                 continue;
402                         default:
403                                 break;
404                         }
405                         break;
406                 case 0x3c:      /* '<', start of XML encoded enumeration */
407                         if(state == ST_LEADSPACE) {
408                                 const asn_INTEGER_enum_map_t *el;
409                                 el = INTEGER_map_enum2value(
410                                         (asn_INTEGER_specifics_t *)
411                                         td->specifics, lstart, lstop);
412                                 if(el) {
413                                         ASN_DEBUG("Found \"%s\" => %ld",
414                                                 el->enum_name, el->nat_value);
415                                         dec_value = el->nat_value;
416                                         state = ST_END_ENUM;
417                                         lp = lstop - 1;
418                                         continue;
419                                 }
420                                 ASN_DEBUG("Unknown identifier for INTEGER");
421                         }
422                         return XPBD_BROKEN_ENCODING;
423                 case 0x3a:      /* ':' */
424                         if(state == ST_HEXCOLON) {
425                                 /* This colon is expected */
426                                 state = ST_HEXDIGIT1;
427                                 continue;
428                         } else if(state == ST_DIGITS) {
429                                 /* The colon here means that we have
430                                  * decoded the first two hexadecimal
431                                  * places as a decimal value.
432                                  * Switch decoding mode. */
433                                 ASN_DEBUG("INTEGER re-evaluate as hex form");
434                                 state = ST_SKIPSPHEX;
435                                 dec_value_start = 0;
436                                 lp = lstart - 1;
437                                 continue;
438                         } else {
439                                 ASN_DEBUG("state %d at %ld", state, (long)(lp - lstart));
440                                 break;
441                         }
442                 /* [A-Fa-f] */
443                 case 0x41:case 0x42:case 0x43:case 0x44:case 0x45:case 0x46:
444                 case 0x61:case 0x62:case 0x63:case 0x64:case 0x65:case 0x66:
445                         switch(state) {
446                         case ST_SKIPSPHEX:
447                         case ST_LEADSPACE: /* Fall through */
448                         case ST_HEXDIGIT1:
449                                 hex_value = lv - ((lv < 0x61) ? 0x41 : 0x61);
450                                 hex_value += 10;
451                                 hex_value <<= 4;
452                                 state = ST_HEXDIGIT2;
453                                 continue;
454                         case ST_HEXDIGIT2:
455                                 hex_value += lv - ((lv < 0x61) ? 0x41 : 0x61);
456                                 hex_value += 10;
457                                 st->buf[st->size++] = (uint8_t)hex_value;
458                                 state = ST_HEXCOLON;
459                                 continue;
460                         case ST_DIGITS:
461                                 ASN_DEBUG("INTEGER re-evaluate as hex form");
462                                 state = ST_SKIPSPHEX;
463                                 dec_value_start = 0;
464                                 lp = lstart - 1;
465                                 continue;
466                         default:
467                                 break;
468                         }
469                         break;
470                 }
471
472                 /* Found extra non-numeric stuff */
473                 ASN_DEBUG("INTEGER :: Found non-numeric 0x%2x at %ld",
474                         lv, (long)(lp - lstart));
475                 state = ST_UNEXPECTED;
476                 break;
477         }
478
479         switch(state) {
480         case ST_END_ENUM:
481                 /* Got a complete and valid enumeration encoded as a tag. */
482                 break;
483         case ST_DIGITS:
484                 dec_value_end = lstop;
485                 /* FALL THROUGH */
486         case ST_DIGITS_TRAILSPACE:
487                 /* The last symbol encountered was a digit. */
488                 switch(asn_strtol_lim(dec_value_start, &dec_value_end, &dec_value)) {
489                 case ASN_STRTOL_OK:
490                         break;
491                 case ASN_STRTOL_ERROR_RANGE:
492                         return XPBD_DECODER_LIMIT;
493                 case ASN_STRTOL_ERROR_INVAL:
494                 case ASN_STRTOL_EXPECT_MORE:
495                 case ASN_STRTOL_EXTRA_DATA:
496                         return XPBD_BROKEN_ENCODING;
497                 }
498                 break;
499         case ST_HEXCOLON:
500         case ST_HEXDIGITS_TRAILSPACE:
501                 st->buf[st->size] = 0;  /* Just in case termination */
502                 return XPBD_BODY_CONSUMED;
503         case ST_HEXDIGIT1:
504         case ST_HEXDIGIT2:
505         case ST_SKIPSPHEX:
506                 return XPBD_BROKEN_ENCODING;
507         case ST_LEADSPACE:
508                 /* Content not found */
509                 return XPBD_NOT_BODY_IGNORE;
510         case ST_WAITDIGITS:
511         case ST_UNEXPECTED:
512                 ASN_DEBUG("INTEGER: No useful digits (state %d)", state);
513                 return XPBD_BROKEN_ENCODING;    /* No digits */
514         }
515
516         /*
517          * Convert the result of parsing of enumeration or a straight
518          * decimal value into a BER representation.
519          */
520         if(asn_long2INTEGER(st, dec_value))
521                 return XPBD_SYSTEM_FAILURE;
522
523         return XPBD_BODY_CONSUMED;
524 }
525
526 asn_dec_rval_t
527 INTEGER_decode_xer(asn_codec_ctx_t *opt_codec_ctx,
528         asn_TYPE_descriptor_t *td, void **sptr, const char *opt_mname,
529                 const void *buf_ptr, size_t size) {
530
531         return xer_decode_primitive(opt_codec_ctx, td,
532                 sptr, sizeof(INTEGER_t), opt_mname,
533                 buf_ptr, size, INTEGER__xer_body_decode);
534 }
535
536 asn_enc_rval_t
537 INTEGER_encode_xer(asn_TYPE_descriptor_t *td, void *sptr,
538         int ilevel, enum xer_encoder_flags_e flags,
539                 asn_app_consume_bytes_f *cb, void *app_key) {
540         const INTEGER_t *st = (const INTEGER_t *)sptr;
541         asn_enc_rval_t er;
542
543         (void)ilevel;
544         (void)flags;
545         
546         if(!st || !st->buf)
547                 _ASN_ENCODE_FAILED;
548
549         er.encoded = INTEGER__dump(td, st, cb, app_key, 1);
550         if(er.encoded < 0) _ASN_ENCODE_FAILED;
551
552         _ASN_ENCODED_OK(er);
553 }
554
555 #ifndef ASN_DISABLE_PER_SUPPORT
556
557 asn_dec_rval_t
558 INTEGER_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
559         asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) {
560         asn_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics;
561         asn_dec_rval_t rval = { RC_OK, 0 };
562         INTEGER_t *st = (INTEGER_t *)*sptr;
563         asn_per_constraint_t *ct;
564         int repeat;
565
566         (void)opt_codec_ctx;
567
568         if(!st) {
569                 st = (INTEGER_t *)(*sptr = CALLOC(1, sizeof(*st)));
570                 if(!st) _ASN_DECODE_FAILED;
571         }
572
573         if(!constraints) constraints = td->per_constraints;
574         ct = constraints ? &constraints->value : 0;
575
576         if(ct && ct->flags & APC_EXTENSIBLE) {
577                 int inext = per_get_few_bits(pd, 1);
578                 if(inext < 0) _ASN_DECODE_STARVED;
579                 if(inext) ct = 0;
580         }
581
582         FREEMEM(st->buf);
583         st->buf = 0;
584         st->size = 0;
585         if(ct) {
586                 if(ct->flags & APC_SEMI_CONSTRAINED) {
587                         st->buf = (uint8_t *)CALLOC(1, 2);
588                         if(!st->buf) _ASN_DECODE_FAILED;
589                         st->size = 1;
590                 } else if(ct->flags & APC_CONSTRAINED && ct->range_bits >= 0) {
591                         size_t size = (ct->range_bits + 7) >> 3;
592                         st->buf = (uint8_t *)MALLOC(1 + size + 1);
593                         if(!st->buf) _ASN_DECODE_FAILED;
594                         st->size = size;
595                 }
596         }
597
598         /* X.691-2008/11, #13.2.2, constrained whole number */
599         if(ct && ct->flags != APC_UNCONSTRAINED) {
600                 /* #11.5.6 */
601                 ASN_DEBUG("Integer with range %d bits", ct->range_bits);
602                 if(ct->range_bits >= 0) {
603                         if((size_t)ct->range_bits > 8 * sizeof(unsigned long))
604                                 _ASN_DECODE_FAILED;
605
606                         if(specs && specs->field_unsigned) {
607                                 unsigned long uvalue;
608                                 if(uper_get_constrained_whole_number(pd,
609                                         &uvalue, ct->range_bits))
610                                         _ASN_DECODE_STARVED;
611                                 ASN_DEBUG("Got value %lu + low %ld",
612                                         uvalue, ct->lower_bound);
613                                 uvalue += ct->lower_bound;
614                                 if(asn_ulong2INTEGER(st, uvalue))
615                                         _ASN_DECODE_FAILED;
616                         } else {
617                                 unsigned long svalue;
618                                 if(uper_get_constrained_whole_number(pd,
619                                         &svalue, ct->range_bits))
620                                         _ASN_DECODE_STARVED;
621                                 ASN_DEBUG("Got value %ld + low %ld",
622                                         svalue, ct->lower_bound);
623                                 svalue += ct->lower_bound;
624                                 if(asn_long2INTEGER(st, svalue))
625                                         _ASN_DECODE_FAILED;
626                         }
627                         return rval;
628                 }
629         } else {
630                 ASN_DEBUG("Decoding unconstrained integer %s", td->name);
631         }
632
633         /* X.691, #12.2.3, #12.2.4 */
634         do {
635                 ssize_t len;
636                 void *p;
637                 int ret;
638
639                 /* Get the PER length */
640                 len = uper_get_length(pd, -1, &repeat);
641                 if(len < 0) _ASN_DECODE_STARVED;
642
643                 p = REALLOC(st->buf, st->size + len + 1);
644                 if(!p) _ASN_DECODE_FAILED;
645                 st->buf = (uint8_t *)p;
646
647                 ret = per_get_many_bits(pd, &st->buf[st->size], 0, 8 * len);
648                 if(ret < 0) _ASN_DECODE_STARVED;
649                 st->size += len;
650         } while(repeat);
651         st->buf[st->size] = 0;  /* JIC */
652
653         /* #12.2.3 */
654         if(ct && ct->lower_bound) {
655                 /*
656                  * TODO: replace by in-place arithmetics.
657                  */
658                 long value;
659                 if(asn_INTEGER2long(st, &value))
660                         _ASN_DECODE_FAILED;
661                 if(asn_long2INTEGER(st, value + ct->lower_bound))
662                         _ASN_DECODE_FAILED;
663         }
664
665         return rval;
666 }
667
668 asn_enc_rval_t
669 INTEGER_encode_uper(asn_TYPE_descriptor_t *td,
670         asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) {
671         asn_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics;
672         asn_enc_rval_t er;
673         INTEGER_t *st = (INTEGER_t *)sptr;
674         const uint8_t *buf;
675         const uint8_t *end;
676         asn_per_constraint_t *ct;
677         long value = 0;
678
679         if(!st || st->size == 0) _ASN_ENCODE_FAILED;
680
681         if(!constraints) constraints = td->per_constraints;
682         ct = constraints ? &constraints->value : 0;
683
684         er.encoded = 0;
685
686         if(ct) {
687                 int inext = 0;
688                 if(specs && specs->field_unsigned) {
689                         unsigned long uval;
690                         if(asn_INTEGER2ulong(st, &uval))
691                                 _ASN_ENCODE_FAILED;
692                         /* Check proper range */
693                         if(ct->flags & APC_SEMI_CONSTRAINED) {
694                                 if(uval < (unsigned long)ct->lower_bound)
695                                         inext = 1;
696                         } else if(ct->range_bits >= 0) {
697                                 if(uval < (unsigned long)ct->lower_bound
698                                 || uval > (unsigned long)ct->upper_bound)
699                                         inext = 1;
700                         }
701                         ASN_DEBUG("Value %lu (%02x/%d) lb %lu ub %lu %s",
702                                 uval, st->buf[0], st->size,
703                                 ct->lower_bound, ct->upper_bound,
704                                 inext ? "ext" : "fix");
705                         value = uval;
706                 } else {
707                         if(asn_INTEGER2long(st, &value))
708                                 _ASN_ENCODE_FAILED;
709                         /* Check proper range */
710                         if(ct->flags & APC_SEMI_CONSTRAINED) {
711                                 if(value < ct->lower_bound)
712                                         inext = 1;
713                         } else if(ct->range_bits >= 0) {
714                                 if(value < ct->lower_bound
715                                 || value > ct->upper_bound)
716                                         inext = 1;
717                         }
718                         ASN_DEBUG("Value %ld (%02x/%d) lb %ld ub %ld %s",
719                                 value, st->buf[0], st->size,
720                                 ct->lower_bound, ct->upper_bound,
721                                 inext ? "ext" : "fix");
722                 }
723                 if(ct->flags & APC_EXTENSIBLE) {
724                         if(per_put_few_bits(po, inext, 1))
725                                 _ASN_ENCODE_FAILED;
726                         if(inext) ct = 0;
727                 } else if(inext) {
728                         _ASN_ENCODE_FAILED;
729                 }
730         }
731
732
733         /* X.691-11/2008, #13.2.2, test if constrained whole number */
734         if(ct && ct->range_bits >= 0) {
735                 /* #11.5.6 -> #11.3 */
736                 ASN_DEBUG("Encoding integer %ld (%lu) with range %d bits",
737                         value, value - ct->lower_bound, ct->range_bits);
738                 unsigned long v = value - ct->lower_bound;
739                 if(uper_put_constrained_whole_number_u(po, v, ct->range_bits))
740                         _ASN_ENCODE_FAILED;
741                 _ASN_ENCODED_OK(er);
742         }
743
744         if(ct && ct->lower_bound) {
745                 ASN_DEBUG("Adjust lower bound to %ld", ct->lower_bound);
746                 /* TODO: adjust lower bound */
747                 _ASN_ENCODE_FAILED;
748         }
749
750         for(buf = st->buf, end = st->buf + st->size; buf < end;) {
751                 ssize_t mayEncode = uper_put_length(po, end - buf);
752                 if(mayEncode < 0)
753                         _ASN_ENCODE_FAILED;
754                 if(per_put_many_bits(po, buf, 8 * mayEncode))
755                         _ASN_ENCODE_FAILED;
756                 buf += mayEncode;
757         }
758
759         _ASN_ENCODED_OK(er);
760 }
761
762 #endif  /* ASN_DISABLE_PER_SUPPORT */
763
764 int
765 asn_INTEGER2long(const INTEGER_t *iptr, long *lptr) {
766         uint8_t *b, *end;
767         size_t size;
768         long l;
769
770         /* Sanity checking */
771         if(!iptr || !iptr->buf || !lptr) {
772                 errno = EINVAL;
773                 return -1;
774         }
775
776         /* Cache the begin/end of the buffer */
777         b = iptr->buf;  /* Start of the INTEGER buffer */
778         size = iptr->size;
779         end = b + size; /* Where to stop */
780
781         if(size > sizeof(long)) {
782                 uint8_t *end1 = end - 1;
783                 /*
784                  * Slightly more advanced processing,
785                  * able to >sizeof(long) bytes,
786                  * when the actual value is small
787                  * (0x0000000000abcdef would yield a fine 0x00abcdef)
788                  */
789                 /* Skip out the insignificant leading bytes */
790                 for(; b < end1; b++) {
791                         switch(*b) {
792                         case 0x00: if((b[1] & 0x80) == 0) continue; break;
793                         case 0xff: if((b[1] & 0x80) != 0) continue; break;
794                         }
795                         break;
796                 }
797
798                 size = end - b;
799                 if(size > sizeof(long)) {
800                         /* Still cannot fit the long */
801                         errno = ERANGE;
802                         return -1;
803                 }
804         }
805
806         /* Shortcut processing of a corner case */
807         if(end == b) {
808                 *lptr = 0;
809                 return 0;
810         }
811
812         /* Perform the sign initialization */
813         /* Actually l = -(*b >> 7); gains nothing, yet unreadable! */
814         if((*b >> 7)) l = -1; else l = 0;
815
816         /* Conversion engine */
817         for(; b < end; b++)
818                 l = (l << 8) | *b;
819
820         *lptr = l;
821         return 0;
822 }
823
824 int
825 asn_INTEGER2ulong(const INTEGER_t *iptr, unsigned long *lptr) {
826         uint8_t *b, *end;
827         unsigned long l;
828         size_t size;
829
830         if(!iptr || !iptr->buf || !lptr) {
831                 errno = EINVAL;
832                 return -1;
833         }
834
835         b = iptr->buf;
836         size = iptr->size;
837         end = b + size;
838
839         /* If all extra leading bytes are zeroes, ignore them */
840         for(; size > sizeof(unsigned long); b++, size--) {
841                 if(*b) {
842                         /* Value won't fit unsigned long */
843                         errno = ERANGE;
844                         return -1;
845                 }
846         }
847
848         /* Conversion engine */
849         for(l = 0; b < end; b++)
850                 l = (l << 8) | *b;
851
852         *lptr = l;
853         return 0;
854 }
855
856 int
857 asn_ulong2INTEGER(INTEGER_t *st, unsigned long value) {
858         uint8_t *buf;
859         uint8_t *end;
860         uint8_t *b;
861         int shr;
862
863         if(value <= LONG_MAX)
864                 return asn_long2INTEGER(st, value);
865
866         buf = (uint8_t *)MALLOC(1 + sizeof(value));
867         if(!buf) return -1;
868
869         end = buf + (sizeof(value) + 1);
870         buf[0] = 0;
871         for(b = buf + 1, shr = (sizeof(long)-1)*8; b < end; shr -= 8, b++)
872                 *b = (uint8_t)(value >> shr);
873
874         if(st->buf) FREEMEM(st->buf);
875         st->buf = buf;
876         st->size = 1 + sizeof(value);
877
878         return 0;
879 }
880
881 int
882 asn_long2INTEGER(INTEGER_t *st, long value) {
883         uint8_t *buf, *bp;
884         uint8_t *p;
885         uint8_t *pstart;
886         uint8_t *pend1;
887         int littleEndian = 1;   /* Run-time detection */
888         int add;
889
890         if(!st) {
891                 errno = EINVAL;
892                 return -1;
893         }
894
895         buf = (uint8_t *)MALLOC(sizeof(value));
896         if(!buf) return -1;
897
898         if(*(char *)&littleEndian) {
899                 pstart = (uint8_t *)&value + sizeof(value) - 1;
900                 pend1 = (uint8_t *)&value;
901                 add = -1;
902         } else {
903                 pstart = (uint8_t *)&value;
904                 pend1 = pstart + sizeof(value) - 1;
905                 add = 1;
906         }
907
908         /*
909          * If the contents octet consists of more than one octet,
910          * then bits of the first octet and bit 8 of the second octet:
911          * a) shall not all be ones; and
912          * b) shall not all be zero.
913          */
914         for(p = pstart; p != pend1; p += add) {
915                 switch(*p) {
916                 case 0x00: if((*(p+add) & 0x80) == 0)
917                                 continue;
918                         break;
919                 case 0xff: if((*(p+add) & 0x80))
920                                 continue;
921                         break;
922                 }
923                 break;
924         }
925         /* Copy the integer body */
926         for(pstart = p, bp = buf, pend1 += add; p != pend1; p += add)
927                 *bp++ = *p;
928
929         if(st->buf) FREEMEM(st->buf);
930         st->buf = buf;
931         st->size = bp - buf;
932
933         return 0;
934 }
935
936 /*
937  * This function is going to be DEPRECATED soon.
938  */
939 enum asn_strtol_result_e
940 asn_strtol(const char *str, const char *end, long *lp) {
941     const char *endp = end;
942
943     switch(asn_strtol_lim(str, &endp, lp)) {
944     case ASN_STRTOL_ERROR_RANGE:
945         return ASN_STRTOL_ERROR_RANGE;
946     case ASN_STRTOL_ERROR_INVAL:
947         return ASN_STRTOL_ERROR_INVAL;
948     case ASN_STRTOL_EXPECT_MORE:
949         return ASN_STRTOL_ERROR_INVAL;  /* Retain old behavior */
950     case ASN_STRTOL_OK:
951         return ASN_STRTOL_OK;
952     case ASN_STRTOL_EXTRA_DATA:
953         return ASN_STRTOL_ERROR_INVAL;  /* Retain old behavior */
954     }
955
956     return ASN_STRTOL_ERROR_INVAL;  /* Retain old behavior */
957 }
958
959 /*
960  * Parse the number in the given string until the given *end position,
961  * returning the position after the last parsed character back using the
962  * same (*end) pointer.
963  * WARNING: This behavior is different from the standard strtol(3).
964  */
965 enum asn_strtol_result_e
966 asn_strtol_lim(const char *str, const char **end, long *lp) {
967         int sign = 1;
968         long l;
969
970         const long upper_boundary = LONG_MAX / 10;
971         long last_digit_max = LONG_MAX % 10;
972
973         if(str >= *end) return ASN_STRTOL_ERROR_INVAL;
974
975         switch(*str) {
976         case '-':
977                 last_digit_max++;
978                 sign = -1;
979         case '+':
980                 str++;
981                 if(str >= *end) {
982                         *end = str;
983                         return ASN_STRTOL_EXPECT_MORE;
984                 }
985         }
986
987         for(l = 0; str < (*end); str++) {
988                 switch(*str) {
989                 case 0x30: case 0x31: case 0x32: case 0x33: case 0x34:
990                 case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: {
991                         int d = *str - '0';
992                         if(l < upper_boundary) {
993                                 l = l * 10 + d;
994                         } else if(l == upper_boundary) {
995                                 if(d <= last_digit_max) {
996                                         if(sign > 0) {
997                                                 l = l * 10 + d;
998                                         } else {
999                                                 sign = 1;
1000                                                 l = -l * 10 - d;
1001                                         }
1002                                 } else {
1003                                         *end = str;
1004                                         return ASN_STRTOL_ERROR_RANGE;
1005                                 }
1006                         } else {
1007                                 *end = str;
1008                                 return ASN_STRTOL_ERROR_RANGE;
1009                         }
1010                     }
1011                     continue;
1012                 default:
1013                     *end = str;
1014                     *lp = sign * l;
1015                     return ASN_STRTOL_EXTRA_DATA;
1016                 }
1017         }
1018
1019         *end = str;
1020         *lp = sign * l;
1021         return ASN_STRTOL_OK;
1022 }
1023