]> git.stg.codes - stg.git/blob - libs/smux/INTEGER.c
Fight Optional
[stg.git] / libs / smux / 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 const 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(const 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                 const char * const 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         const asn_INTEGER_enum_map_t *vemap;
212         const 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         const 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         unsigned long v = 0;
679
680         if(!st || st->size == 0) ASN__ENCODE_FAILED;
681
682         if(!constraints) constraints = td->per_constraints;
683         ct = constraints ? &constraints->value : 0;
684
685         er.encoded = 0;
686
687         if(ct) {
688                 int inext = 0;
689                 if(specs && specs->field_unsigned) {
690                         unsigned long uval;
691                         if(asn_INTEGER2ulong(st, &uval))
692                                 ASN__ENCODE_FAILED;
693                         /* Check proper range */
694                         if(ct->flags & APC_SEMI_CONSTRAINED) {
695                                 if(uval < (unsigned long)ct->lower_bound)
696                                         inext = 1;
697                         } else if(ct->range_bits >= 0) {
698                                 if(uval < (unsigned long)ct->lower_bound
699                                 || uval > (unsigned long)ct->upper_bound)
700                                         inext = 1;
701                         }
702                         ASN_DEBUG("Value %lu (%02x/%d) lb %lu ub %lu %s",
703                                 uval, st->buf[0], st->size,
704                                 ct->lower_bound, ct->upper_bound,
705                                 inext ? "ext" : "fix");
706                         value = uval;
707                 } else {
708                         if(asn_INTEGER2long(st, &value))
709                                 ASN__ENCODE_FAILED;
710                         /* Check proper range */
711                         if(ct->flags & APC_SEMI_CONSTRAINED) {
712                                 if(value < ct->lower_bound)
713                                         inext = 1;
714                         } else if(ct->range_bits >= 0) {
715                                 if(value < ct->lower_bound
716                                 || value > ct->upper_bound)
717                                         inext = 1;
718                         }
719                         ASN_DEBUG("Value %ld (%02x/%d) lb %ld ub %ld %s",
720                                 value, st->buf[0], st->size,
721                                 ct->lower_bound, ct->upper_bound,
722                                 inext ? "ext" : "fix");
723                 }
724                 if(ct->flags & APC_EXTENSIBLE) {
725                         if(per_put_few_bits(po, inext, 1))
726                                 ASN__ENCODE_FAILED;
727                         if(inext) ct = 0;
728                 } else if(inext) {
729                         ASN__ENCODE_FAILED;
730                 }
731         }
732
733
734         /* X.691-11/2008, #13.2.2, test if constrained whole number */
735         if(ct && ct->range_bits >= 0) {
736                 /* #11.5.6 -> #11.3 */
737                 ASN_DEBUG("Encoding integer %ld (%lu) with range %d bits",
738                         value, value - ct->lower_bound, ct->range_bits);
739                 v = value - ct->lower_bound;
740                 if(uper_put_constrained_whole_number_u(po, v, ct->range_bits))
741                         ASN__ENCODE_FAILED;
742                 ASN__ENCODED_OK(er);
743         }
744
745         if(ct && ct->lower_bound) {
746                 ASN_DEBUG("Adjust lower bound to %ld", ct->lower_bound);
747                 /* TODO: adjust lower bound */
748                 ASN__ENCODE_FAILED;
749         }
750
751         for(buf = st->buf, end = st->buf + st->size; buf < end;) {
752                 ssize_t mayEncode = uper_put_length(po, end - buf);
753                 if(mayEncode < 0)
754                         ASN__ENCODE_FAILED;
755                 if(per_put_many_bits(po, buf, 8 * mayEncode))
756                         ASN__ENCODE_FAILED;
757                 buf += mayEncode;
758         }
759
760         ASN__ENCODED_OK(er);
761 }
762
763 #endif  /* ASN_DISABLE_PER_SUPPORT */
764
765 int
766 asn_INTEGER2long(const INTEGER_t *iptr, long *lptr) {
767         uint8_t *b, *end;
768         size_t size;
769         long l;
770
771         /* Sanity checking */
772         if(!iptr || !iptr->buf || !lptr) {
773                 errno = EINVAL;
774                 return -1;
775         }
776
777         /* Cache the begin/end of the buffer */
778         b = iptr->buf;  /* Start of the INTEGER buffer */
779         size = iptr->size;
780         end = b + size; /* Where to stop */
781
782         if(size > sizeof(long)) {
783                 uint8_t *end1 = end - 1;
784                 /*
785                  * Slightly more advanced processing,
786                  * able to >sizeof(long) bytes,
787                  * when the actual value is small
788                  * (0x0000000000abcdef would yield a fine 0x00abcdef)
789                  */
790                 /* Skip out the insignificant leading bytes */
791                 for(; b < end1; b++) {
792                         switch(*b) {
793                         case 0x00: if((b[1] & 0x80) == 0) continue; break;
794                         case 0xff: if((b[1] & 0x80) != 0) continue; break;
795                         }
796                         break;
797                 }
798
799                 size = end - b;
800                 if(size > sizeof(long)) {
801                         /* Still cannot fit the long */
802                         errno = ERANGE;
803                         return -1;
804                 }
805         }
806
807         /* Shortcut processing of a corner case */
808         if(end == b) {
809                 *lptr = 0;
810                 return 0;
811         }
812
813         /* Perform the sign initialization */
814         /* Actually l = -(*b >> 7); gains nothing, yet unreadable! */
815         if((*b >> 7)) l = -1; else l = 0;
816
817         /* Conversion engine */
818         for(; b < end; b++)
819                 l = (l << 8) | *b;
820
821         *lptr = l;
822         return 0;
823 }
824
825 int
826 asn_INTEGER2ulong(const INTEGER_t *iptr, unsigned long *lptr) {
827         uint8_t *b, *end;
828         unsigned long l;
829         size_t size;
830
831         if(!iptr || !iptr->buf || !lptr) {
832                 errno = EINVAL;
833                 return -1;
834         }
835
836         b = iptr->buf;
837         size = iptr->size;
838         end = b + size;
839
840         /* If all extra leading bytes are zeroes, ignore them */
841         for(; size > sizeof(unsigned long); b++, size--) {
842                 if(*b) {
843                         /* Value won't fit unsigned long */
844                         errno = ERANGE;
845                         return -1;
846                 }
847         }
848
849         /* Conversion engine */
850         for(l = 0; b < end; b++)
851                 l = (l << 8) | *b;
852
853         *lptr = l;
854         return 0;
855 }
856
857 int
858 asn_ulong2INTEGER(INTEGER_t *st, unsigned long value) {
859         uint8_t *buf;
860         uint8_t *end;
861         uint8_t *b;
862         int shr;
863
864         if(value <= LONG_MAX)
865                 return asn_long2INTEGER(st, value);
866
867         buf = (uint8_t *)MALLOC(1 + sizeof(value));
868         if(!buf) return -1;
869
870         end = buf + (sizeof(value) + 1);
871         buf[0] = 0;
872         for(b = buf + 1, shr = (sizeof(long)-1)*8; b < end; shr -= 8, b++)
873                 *b = (uint8_t)(value >> shr);
874
875         if(st->buf) FREEMEM(st->buf);
876         st->buf = buf;
877         st->size = 1 + sizeof(value);
878
879         return 0;
880 }
881
882 int
883 asn_long2INTEGER(INTEGER_t *st, long value) {
884         uint8_t *buf, *bp;
885         uint8_t *p;
886         uint8_t *pstart;
887         uint8_t *pend1;
888         int littleEndian = 1;   /* Run-time detection */
889         int add;
890
891         if(!st) {
892                 errno = EINVAL;
893                 return -1;
894         }
895
896         buf = (uint8_t *)MALLOC(sizeof(value));
897         if(!buf) return -1;
898
899         if(*(char *)&littleEndian) {
900                 pstart = (uint8_t *)&value + sizeof(value) - 1;
901                 pend1 = (uint8_t *)&value;
902                 add = -1;
903         } else {
904                 pstart = (uint8_t *)&value;
905                 pend1 = pstart + sizeof(value) - 1;
906                 add = 1;
907         }
908
909         /*
910          * If the contents octet consists of more than one octet,
911          * then bits of the first octet and bit 8 of the second octet:
912          * a) shall not all be ones; and
913          * b) shall not all be zero.
914          */
915         for(p = pstart; p != pend1; p += add) {
916                 switch(*p) {
917                 case 0x00: if((*(p+add) & 0x80) == 0)
918                                 continue;
919                         break;
920                 case 0xff: if((*(p+add) & 0x80))
921                                 continue;
922                         break;
923                 }
924                 break;
925         }
926         /* Copy the integer body */
927         for(pstart = p, bp = buf, pend1 += add; p != pend1; p += add)
928                 *bp++ = *p;
929
930         if(st->buf) FREEMEM(st->buf);
931         st->buf = buf;
932         st->size = bp - buf;
933
934         return 0;
935 }
936
937 /*
938  * This function is going to be DEPRECATED soon.
939  */
940 enum asn_strtol_result_e
941 asn_strtol(const char *str, const char *end, long *lp) {
942     const char *endp = end;
943
944     switch(asn_strtol_lim(str, &endp, lp)) {
945     case ASN_STRTOL_ERROR_RANGE:
946         return ASN_STRTOL_ERROR_RANGE;
947     case ASN_STRTOL_ERROR_INVAL:
948         return ASN_STRTOL_ERROR_INVAL;
949     case ASN_STRTOL_EXPECT_MORE:
950         return ASN_STRTOL_ERROR_INVAL;  /* Retain old behavior */
951     case ASN_STRTOL_OK:
952         return ASN_STRTOL_OK;
953     case ASN_STRTOL_EXTRA_DATA:
954         return ASN_STRTOL_ERROR_INVAL;  /* Retain old behavior */
955     }
956
957     return ASN_STRTOL_ERROR_INVAL;  /* Retain old behavior */
958 }
959
960 /*
961  * Parse the number in the given string until the given *end position,
962  * returning the position after the last parsed character back using the
963  * same (*end) pointer.
964  * WARNING: This behavior is different from the standard strtol(3).
965  */
966 enum asn_strtol_result_e
967 asn_strtol_lim(const char *str, const char **end, long *lp) {
968         int sign = 1;
969         long l;
970
971         const long upper_boundary = LONG_MAX / 10;
972         long last_digit_max = LONG_MAX % 10;
973
974         if(str >= *end) return ASN_STRTOL_ERROR_INVAL;
975
976         switch(*str) {
977         case '-':
978                 last_digit_max++;
979                 sign = -1;
980                 /* FALL THROUGH */
981         case '+':
982                 str++;
983                 if(str >= *end) {
984                         *end = str;
985                         return ASN_STRTOL_EXPECT_MORE;
986                 }
987         }
988
989         for(l = 0; str < (*end); str++) {
990                 switch(*str) {
991                 case 0x30: case 0x31: case 0x32: case 0x33: case 0x34:
992                 case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: {
993                         int d = *str - '0';
994                         if(l < upper_boundary) {
995                                 l = l * 10 + d;
996                         } else if(l == upper_boundary) {
997                                 if(d <= last_digit_max) {
998                                         if(sign > 0) {
999                                                 l = l * 10 + d;
1000                                         } else {
1001                                                 sign = 1;
1002                                                 l = -l * 10 - d;
1003                                         }
1004                                 } else {
1005                                         *end = str;
1006                                         return ASN_STRTOL_ERROR_RANGE;
1007                                 }
1008                         } else {
1009                                 *end = str;
1010                                 return ASN_STRTOL_ERROR_RANGE;
1011                         }
1012                     }
1013                     continue;
1014                 default:
1015                     *end = str;
1016                     *lp = sign * l;
1017                     return ASN_STRTOL_EXTRA_DATA;
1018                 }
1019         }
1020
1021         *end = str;
1022         *lp = sign * l;
1023         return ASN_STRTOL_OK;
1024 }
1025