SIM-115: update simulator to use latest E2SM KPM version 3
[sim/e2-interface.git] / e2sim / asn1c / OBJECT_IDENTIFIER.c
1 /*-
2  * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
3  * Redistribution and modifications are permitted subject to BSD license.
4  */
5 #include <asn_internal.h>
6 #include <INTEGER.h>
7 #include <OBJECT_IDENTIFIER.h>
8 #include <asn_codecs_prim.h>
9 #include <limits.h>     /* for CHAR_BIT */
10 #include <errno.h>
11 #include <inttypes.h>
12
13 /*
14  * OBJECT IDENTIFIER basic type description.
15  */
16 static const ber_tlv_tag_t asn_DEF_OBJECT_IDENTIFIER_tags[] = {
17     (ASN_TAG_CLASS_UNIVERSAL | (6 << 2))
18 };
19 asn_TYPE_operation_t asn_OP_OBJECT_IDENTIFIER = {
20     ASN__PRIMITIVE_TYPE_free,
21 #if !defined(ASN_DISABLE_PRINT_SUPPORT)
22     OBJECT_IDENTIFIER_print,
23 #else
24     0,
25 #endif  /* !defined(ASN_DISABLE_PRINT_SUPPORT) */
26     OCTET_STRING_compare,   /* Implemented in terms of a string comparison */
27 #if !defined(ASN_DISABLE_BER_SUPPORT)
28     ber_decode_primitive,
29     der_encode_primitive,
30 #else
31     0,
32     0,
33 #endif  /* !defined(ASN_DISABLE_BER_SUPPORT) */
34 #if !defined(ASN_DISABLE_XER_SUPPORT)
35     OBJECT_IDENTIFIER_decode_xer,
36     OBJECT_IDENTIFIER_encode_xer,
37 #else
38     0,
39     0,
40 #endif  /* !defined(ASN_DISABLE_XER_SUPPORT) */
41 #if !defined(ASN_DISABLE_JER_SUPPORT)
42     OBJECT_IDENTIFIER_encode_jer,
43 #else
44     0,
45 #endif  /* !defined(ASN_DISABLE_JER_SUPPORT) */
46 #if !defined(ASN_DISABLE_OER_SUPPORT)
47     OBJECT_IDENTIFIER_decode_oer,
48     OBJECT_IDENTIFIER_encode_oer,
49 #else
50     0,
51     0,
52 #endif  /* !defined(ASN_DISABLE_OER_SUPPORT) */
53 #if !defined(ASN_DISABLE_UPER_SUPPORT)
54     OCTET_STRING_decode_uper,
55     OCTET_STRING_encode_uper,
56 #else
57     0,
58     0,
59 #endif  /* !defined(ASN_DISABLE_UPER_SUPPORT) */
60 #if !defined(ASN_DISABLE_APER_SUPPORT)
61     OCTET_STRING_decode_aper,
62     OCTET_STRING_encode_aper,
63 #else
64     0,
65     0,
66 #endif  /* !defined(ASN_DISABLE_APER_SUPPORT) */
67 #if !defined(ASN_DISABLE_RFILL_SUPPORT)
68     OBJECT_IDENTIFIER_random_fill,
69 #else
70     0,
71 #endif  /* !defined(ASN_DISABLE_RFILL_SUPPORT) */
72     0  /* Use generic outmost tag fetcher */
73 };
74 asn_TYPE_descriptor_t asn_DEF_OBJECT_IDENTIFIER = {
75     "OBJECT IDENTIFIER",
76     "OBJECT_IDENTIFIER",
77     &asn_OP_OBJECT_IDENTIFIER,
78     asn_DEF_OBJECT_IDENTIFIER_tags,
79     sizeof(asn_DEF_OBJECT_IDENTIFIER_tags)
80         / sizeof(asn_DEF_OBJECT_IDENTIFIER_tags[0]),
81     asn_DEF_OBJECT_IDENTIFIER_tags,  /* Same as above */
82     sizeof(asn_DEF_OBJECT_IDENTIFIER_tags)
83         / sizeof(asn_DEF_OBJECT_IDENTIFIER_tags[0]),
84     {
85 #if !defined(ASN_DISABLE_OER_SUPPORT)
86         0,
87 #endif  /* !defined(ASN_DISABLE_OER_SUPPORT) */
88 #if !defined(ASN_DISABLE_UPER_SUPPORT) || !defined(ASN_DISABLE_APER_SUPPORT)
89         0,
90 #endif  /* !defined(ASN_DISABLE_UPER_SUPPORT) || !defined(ASN_DISABLE_APER_SUPPORT) */
91         OBJECT_IDENTIFIER_constraint
92     },
93     0, 0,  /* No members */
94     0  /* No specifics */
95 };
96
97 int
98 OBJECT_IDENTIFIER_constraint(const asn_TYPE_descriptor_t *td, const void *sptr,
99                              asn_app_constraint_failed_f *ctfailcb,
100                              void *app_key) {
101     const OBJECT_IDENTIFIER_t *st = (const OBJECT_IDENTIFIER_t *)sptr;
102
103         if(st && st->buf) {
104                 if(st->size < 1) {
105                         ASN__CTFAIL(app_key, td, sptr,
106                                 "%s: at least one numerical value "
107                                 "expected (%s:%d)",
108                                 td->name, __FILE__, __LINE__);
109                         return -1;
110                 }
111         } else {
112                 ASN__CTFAIL(app_key, td, sptr,
113                         "%s: value not given (%s:%d)",
114                         td->name, __FILE__, __LINE__);
115                 return -1;
116         }
117
118         return 0;
119 }
120
121 static ssize_t
122 OBJECT_IDENTIFIER_get_first_arcs(const uint8_t *arcbuf, size_t arcbuf_len,
123                                  asn_oid_arc_t *arc0, asn_oid_arc_t *arc1) {
124     asn_oid_arc_t value;
125
126     ssize_t rd = OBJECT_IDENTIFIER_get_single_arc(arcbuf, arcbuf_len, &value);
127     if(rd <= 0) return rd;
128
129     if(value >= 80) {
130         *arc0 = 2;
131         *arc1 = value - 80;
132     } else if(value >= 40) {
133         *arc0 = 1;
134         *arc1 = value - 40;
135     } else {
136         *arc0 = 0;
137         *arc1 = value;
138     }
139
140     return rd;
141 }
142
143 ssize_t
144 OBJECT_IDENTIFIER_get_single_arc(const uint8_t *arcbuf, size_t arcbuf_len,
145                                  asn_oid_arc_t *ret_value) {
146     const uint8_t *b = arcbuf;
147     const uint8_t *arcend = arcbuf + arcbuf_len; /* End of arc */
148
149     if(arcbuf == arcend) {
150         return 0;
151     } else {
152         asn_oid_arc_t accum;
153         asn_oid_arc_t upper_limit = (ASN_OID_ARC_MAX >> 7);
154         /* When the value reaches "upper_limit", it can take */
155         /* at most one more digit. If it exceeds "upper_limit" */
156         /* but there are more digits - it's an Overflow condition */
157         /* Gather all bits into the accumulator */
158         for(accum = 0; b < arcend; b++) {
159             accum = (accum << 7) | (*b & ~0x80);
160             if((*b & 0x80) == 0) { // no more digits
161                 if(accum <= ASN_OID_ARC_MAX) {
162                     *ret_value = accum;
163                     return 1 + (b - arcbuf);
164                 } else {
165                     errno = ERANGE; /* Overflow */
166                     return -1;
167                 }
168             } else { // to make sure we aren't wrapping around
169               if(accum > upper_limit) {
170                     errno = ERANGE; /* Overflow */
171                     return -1;
172               }
173             }
174         }
175         errno = EINVAL;
176         return -1;
177     }
178
179 }
180
181 ssize_t
182 OBJECT_IDENTIFIER__dump_body(const OBJECT_IDENTIFIER_t *st,
183                              asn_app_consume_bytes_f *cb, void *app_key) {
184     char scratch[32];
185     asn_oid_arc_t arc0 = 0;
186     asn_oid_arc_t arc1 = 0;
187     size_t produced = 0;
188     size_t off = 0;
189     ssize_t rd;
190     int ret;
191
192     rd = OBJECT_IDENTIFIER_get_first_arcs(st->buf, st->size, &arc0, &arc1);
193     if(rd <= 0) {
194         return -1;
195     }
196
197     ret = snprintf(scratch, sizeof(scratch), "%"PRIu32".%"PRIu32, arc0, arc1);
198     if(ret >= (ssize_t)sizeof(scratch)) {
199         return -1;
200     }
201     produced += ret;
202     if(cb(scratch, ret, app_key) < 0)
203         return -1;
204
205     for(off = rd; ; ) {
206         asn_oid_arc_t arc;
207         rd = OBJECT_IDENTIFIER_get_single_arc(st->buf + off, st->size - off,
208                                               &arc);
209         if(rd < 0) {
210             return -1;
211         } else if(rd == 0) {
212             /* No more arcs. */
213             break;
214         } else {
215             off += rd;
216             assert(off <= st->size);
217             ret = snprintf(scratch, sizeof(scratch), ".%" PRIu32, arc);
218             if(ret >= (ssize_t)sizeof(scratch)) {
219                 return -1;
220             }
221             produced += ret;
222             if(cb(scratch, ret, app_key) < 0) return -1;
223         }
224     }
225
226     if(off != st->size) {
227         ASN_DEBUG("Could not scan to the end of Object Identifier");
228         return -1;
229     }
230
231         return produced;
232 }
233
234 ssize_t
235 OBJECT_IDENTIFIER_get_arcs(const OBJECT_IDENTIFIER_t *st, asn_oid_arc_t *arcs,
236                            size_t arc_slots) {
237     asn_oid_arc_t arc0 = 0;
238     asn_oid_arc_t arc1 = 0;
239     size_t num_arcs = 0;
240     size_t off;
241     ssize_t rd;
242
243     if(!st || !st->buf) {
244         errno = EINVAL;
245         return -1;
246     }
247
248     rd = OBJECT_IDENTIFIER_get_first_arcs(st->buf, st->size, &arc0, &arc1);
249     if(rd <= 0) {
250         return -1;
251     }
252     num_arcs = 2;
253     switch(arc_slots) {
254     default:
255     case 2:
256         arcs[1] = arc1;
257         /* Fall through */
258     case 1:
259         arcs[0] = arc0;
260         /* Fall through */
261     case 0:
262         break;
263     }
264
265     for(off = rd; ; ) {
266         asn_oid_arc_t arc;
267         rd = OBJECT_IDENTIFIER_get_single_arc(st->buf + off, st->size - off,
268                                               &arc);
269         if(rd < 0) {
270             return -1;
271         } else if(rd == 0) {
272             /* No more arcs. */
273             break;
274         } else {
275             off += rd;
276             if(num_arcs < arc_slots) {
277                 arcs[num_arcs] = arc;
278             }
279             num_arcs++;
280         }
281     }
282
283     if(off != st->size) {
284         return -1;
285     }
286
287     return num_arcs;
288 }
289
290
291 /*
292  * Save the single value as an object identifier arc.
293  */
294 ssize_t
295 OBJECT_IDENTIFIER_set_single_arc(uint8_t *arcbuf, size_t arcbuf_len,
296                                  asn_oid_arc_t value) {
297     /*
298          * The following conditions must hold:
299          * assert(arcbuf);
300          */
301     uint8_t scratch[((sizeof(value) * CHAR_BIT + 6) / 7)];
302     uint8_t *scratch_end = &scratch[sizeof(scratch)-1];
303     uint8_t *b;
304     size_t result_len;
305     uint8_t mask;
306
307     for(b = scratch_end, mask = 0; ; mask = 0x80, b--) {
308         *b = mask | (value & 0x7f);
309         value >>= 7;
310         if(!value) {
311             break;
312         }
313     }
314
315     result_len = (scratch_end - b) + 1;
316
317     if(result_len > arcbuf_len) {
318         return -1;
319     }
320
321     memcpy(arcbuf, b, result_len);
322
323         return result_len;
324 }
325
326 int
327 OBJECT_IDENTIFIER_set_arcs(OBJECT_IDENTIFIER_t *st, const asn_oid_arc_t *arcs,
328                            size_t arc_slots) {
329     uint8_t *buf;
330     uint8_t *bp;
331     ssize_t wrote;
332     asn_oid_arc_t arc0;
333     asn_oid_arc_t arc1;
334     size_t size;
335     size_t i;
336
337     if(!st || !arcs || arc_slots < 2) {
338         errno = EINVAL;
339                 return -1;
340         }
341
342     arc0 = arcs[0];
343     arc1 = arcs[1];
344
345         if(arc0 <= 1) {
346                 if(arc1 >= 40) {
347                         /* 8.19.4: At most 39 subsequent values (including 0) */
348                         errno = ERANGE;
349                         return -1;
350                 }
351     } else if(arc0 == 2) {
352         if(arc1 > ASN_OID_ARC_MAX - 80) {
353             errno = ERANGE;
354             return -1;
355         }
356     } else if(arc0 > 2) {
357         /* 8.19.4: Only three values are allocated from the root node */
358         errno = ERANGE;
359         return -1;
360     }
361
362     /*
363          * After above tests it is known that the value of arc0 is completely
364          * trustworthy (0..2). However, the arc1's value is still meaningless.
365          */
366
367     /*
368      * Roughly estimate the maximum size necessary to encode these arcs.
369      * This estimation implicitly takes in account the following facts,
370      * that cancel each other:
371      *  * the first two arcs are encoded in a single value.
372      *  * the first value may require more space (+1 byte)
373      *  * the value of the first arc which is in range (0..2)
374      */
375     size = ((sizeof(asn_oid_arc_t) * CHAR_BIT + 6) / 7) * arc_slots;
376     bp = buf = (uint8_t *)MALLOC(size + 1);
377     if(!buf) {
378         /* ENOMEM */
379         return -1;
380     }
381
382     wrote = OBJECT_IDENTIFIER_set_single_arc(bp, size, arc0 * 40 + arc1);
383     if(wrote <= 0) {
384         FREEMEM(buf);
385         return -1;
386     }
387     assert((size_t)wrote <= size);
388     bp += wrote;
389     size -= wrote;
390
391     for(i = 2; i < arc_slots; i++) {
392                 wrote = OBJECT_IDENTIFIER_set_single_arc(bp, size, arcs[i]);
393         if(wrote <= 0) {
394             FREEMEM(buf);
395             return -1;
396         }
397         assert((size_t)wrote <= size);
398         bp += wrote;
399         size -= wrote;
400     }
401
402     /*
403          * Replace buffer.
404          */
405         st->size = bp - buf;
406         bp = st->buf;
407         st->buf = buf;
408         st->buf[st->size] = '\0';
409         if(bp) FREEMEM(bp);
410
411         return 0;
412 }
413
414 ssize_t
415 OBJECT_IDENTIFIER_parse_arcs(const char *oid_text, ssize_t oid_txt_length,
416                              asn_oid_arc_t *arcs, size_t arcs_count,
417                              const char **opt_oid_text_end) {
418     size_t num_arcs = 0;
419     const char *oid_end;
420         enum {
421                 ST_LEADSPACE,
422                 ST_TAILSPACE,
423                 ST_AFTERVALUE,  /* Next character ought to be '.' or a space */
424                 ST_WAITDIGITS   /* Next character is expected to be a digit */
425         } state = ST_LEADSPACE;
426
427         if(!oid_text || oid_txt_length < -1 || (arcs_count && !arcs)) {
428                 if(opt_oid_text_end) *opt_oid_text_end = oid_text;
429                 errno = EINVAL;
430                 return -1;
431         }
432
433         if(oid_txt_length == -1)
434                 oid_txt_length = strlen(oid_text);
435
436 #define _OID_CAPTURE_ARC(oid_text, oid_end)                       \
437     do {                                                          \
438         const char *endp = oid_end;                               \
439         unsigned long value;                                      \
440         switch(asn_strtoul_lim(oid_text, &endp, &value)) {        \
441         case ASN_STRTOX_EXTRA_DATA:                               \
442         case ASN_STRTOX_OK:                                       \
443             if(value <= ASN_OID_ARC_MAX) {                        \
444                 if(num_arcs < arcs_count) arcs[num_arcs] = value; \
445                 num_arcs++;                                       \
446                 oid_text = endp - 1;                              \
447                 break;                                            \
448             }                                                     \
449             /* Fall through */                                    \
450         case ASN_STRTOX_ERROR_RANGE:                              \
451             if(opt_oid_text_end) *opt_oid_text_end = oid_text;    \
452             errno = ERANGE;                                       \
453             return -1;                                            \
454         case ASN_STRTOX_ERROR_INVAL:                              \
455         case ASN_STRTOX_EXPECT_MORE:                              \
456             if(opt_oid_text_end) *opt_oid_text_end = oid_text;    \
457             errno = EINVAL;                                       \
458             return -1;                                            \
459         }                                                         \
460     } while(0)
461
462     for(oid_end = oid_text + oid_txt_length; oid_text<oid_end; oid_text++) {
463             switch(*oid_text) {
464             case 0x09: case 0x0a: case 0x0d: case 0x20: /* whitespace */
465                 switch(state) {
466                 case ST_LEADSPACE:
467                 case ST_TAILSPACE:
468                         continue;
469                 case ST_AFTERVALUE:
470                         state = ST_TAILSPACE;
471                         continue;
472                 case ST_WAITDIGITS:
473                         break;  /* Digits expected after ".", got whitespace */
474                 }
475                 break;
476             case 0x2e:  /* '.' */
477                 switch(state) {
478                 case ST_LEADSPACE:
479                 case ST_TAILSPACE:
480                 case ST_WAITDIGITS:
481                         if(opt_oid_text_end)
482                                 *opt_oid_text_end = oid_text;
483                         errno = EINVAL; /* Broken OID */
484                         return -1;
485                         break;
486                 case ST_AFTERVALUE:
487                         state = ST_WAITDIGITS;
488                         continue;
489                 }
490                 break;
491             case 0x30: case 0x31: case 0x32: case 0x33: case 0x34:
492             case 0x35: case 0x36: case 0x37: case 0x38: case 0x39:
493                 switch(state) {
494                 case ST_TAILSPACE:
495                 case ST_AFTERVALUE:
496                         if(opt_oid_text_end)
497                                 *opt_oid_text_end = oid_text;
498                         errno = EINVAL; /* "1. 1" => broken OID */
499                         return -1;
500                 case ST_LEADSPACE:
501                 case ST_WAITDIGITS:
502                         _OID_CAPTURE_ARC(oid_text, oid_end);
503                         state = ST_AFTERVALUE;
504                         continue;
505                 }
506                 break;
507             default:
508                 /* Unexpected symbols */
509                 state = ST_WAITDIGITS;
510                 break;
511             } /* switch() */
512             break;
513         } /* for() */
514
515
516         if(opt_oid_text_end) *opt_oid_text_end = oid_text;
517
518         /* Finalize last arc */
519         switch(state) {
520         case ST_LEADSPACE:
521                 return 0; /* No OID found in input data */
522         case ST_WAITDIGITS:
523                 errno = EINVAL; /* Broken OID */
524                 return -1;
525         case ST_AFTERVALUE:
526         case ST_TAILSPACE:
527                 return num_arcs;
528         }
529
530         errno = EINVAL; /* Broken OID */
531         return -1;
532 }