Adding initial code jy.oak@samsung.com
[ric-app/kpimon.git] / asn1c_defs / all-defs / per_support.c
1 /*\r
2  * Copyright (c) 2005-2017 Lev Walkin <vlm@lionet.info>. All rights reserved.\r
3  * Redistribution and modifications are permitted subject to BSD license.\r
4  */\r
5 #include <asn_system.h>\r
6 #include <asn_internal.h>\r
7 #include <per_support.h>\r
8 \r
9 /*\r
10  * X.691-201508 #10.9 General rules for encoding a length determinant.\r
11  * Get the optionally constrained length "n" from the stream.\r
12  */\r
13 ssize_t\r
14 uper_get_length(asn_per_data_t *pd, int ebits, size_t lower_bound,\r
15                 int *repeat) {\r
16     ssize_t value;\r
17 \r
18     *repeat = 0;\r
19 \r
20     /* #11.9.4.1 Encoding if constrained (according to effective bits) */\r
21     if(ebits >= 0 && ebits <= 16) {\r
22         value = per_get_few_bits(pd, ebits);\r
23         if(value >= 0) value += lower_bound;\r
24         return value;\r
25     }\r
26 \r
27         value = per_get_few_bits(pd, 8);\r
28     if((value & 0x80) == 0) { /* #11.9.3.6 */\r
29         return (value & 0x7F);\r
30     } else if((value & 0x40) == 0) { /* #11.9.3.7 */\r
31         /* bit 8 ... set to 1 and bit 7 ... set to zero */\r
32         value = ((value & 0x3f) << 8) | per_get_few_bits(pd, 8);\r
33         return value; /* potential -1 from per_get_few_bits passes through. */\r
34     } else if(value < 0) {\r
35         ASN_DEBUG("END of stream reached for PER");\r
36         return -1;\r
37     }\r
38     value &= 0x3f; /* this is "m" from X.691, #11.9.3.8 */\r
39     if(value < 1 || value > 4) {\r
40         return -1; /* Prohibited by #11.9.3.8 */\r
41     }\r
42     *repeat = 1;\r
43     return (16384 * value);\r
44 }\r
45 \r
46 /*\r
47  * Get the normally small length "n".\r
48  * This procedure used to decode length of extensions bit-maps\r
49  * for SET and SEQUENCE types.\r
50  */\r
51 ssize_t\r
52 uper_get_nslength(asn_per_data_t *pd) {\r
53         ssize_t length;\r
54 \r
55         ASN_DEBUG("Getting normally small length");\r
56 \r
57         if(per_get_few_bits(pd, 1) == 0) {\r
58                 length = per_get_few_bits(pd, 6) + 1;\r
59                 if(length <= 0) return -1;\r
60                 ASN_DEBUG("l=%d", (int)length);\r
61                 return length;\r
62         } else {\r
63                 int repeat;\r
64                 length = uper_get_length(pd, -1, 0, &repeat);\r
65                 if(length >= 0 && !repeat) return length;\r
66                 return -1; /* Error, or do not support >16K extensions */\r
67         }\r
68 }\r
69 \r
70 /*\r
71  * Get the normally small non-negative whole number.\r
72  * X.691, #10.6\r
73  */\r
74 ssize_t\r
75 uper_get_nsnnwn(asn_per_data_t *pd) {\r
76         ssize_t value;\r
77 \r
78         value = per_get_few_bits(pd, 7);\r
79         if(value & 64) {        /* implicit (value < 0) */\r
80                 value &= 63;\r
81                 value <<= 2;\r
82                 value |= per_get_few_bits(pd, 2);\r
83                 if(value & 128) /* implicit (value < 0) */\r
84                         return -1;\r
85                 if(value == 0)\r
86                         return 0;\r
87                 if(value >= 3)\r
88                         return -1;\r
89                 value = per_get_few_bits(pd, 8 * value);\r
90                 return value;\r
91         }\r
92 \r
93         return value;\r
94 }\r
95 \r
96 /*\r
97  * X.691-11/2008, #11.6\r
98  * Encoding of a normally small non-negative whole number\r
99  */\r
100 int\r
101 uper_put_nsnnwn(asn_per_outp_t *po, int n) {\r
102         int bytes;\r
103 \r
104         if(n <= 63) {\r
105                 if(n < 0) return -1;\r
106                 return per_put_few_bits(po, n, 7);\r
107         }\r
108         if(n < 256)\r
109                 bytes = 1;\r
110         else if(n < 65536)\r
111                 bytes = 2;\r
112         else if(n < 256 * 65536)\r
113                 bytes = 3;\r
114         else\r
115                 return -1;      /* This is not a "normally small" value */\r
116         if(per_put_few_bits(po, bytes, 8))\r
117                 return -1;\r
118 \r
119         return per_put_few_bits(po, n, 8 * bytes);\r
120 }\r
121 \r
122 \r
123 /* X.691-2008/11, #11.5.6 -> #11.3 */\r
124 int uper_get_constrained_whole_number(asn_per_data_t *pd, unsigned long *out_value, int nbits) {\r
125         unsigned long lhalf;    /* Lower half of the number*/\r
126         long half;\r
127 \r
128         if(nbits <= 31) {\r
129                 half = per_get_few_bits(pd, nbits);\r
130                 if(half < 0) return -1;\r
131                 *out_value = half;\r
132                 return 0;\r
133         }\r
134 \r
135         if((size_t)nbits > 8 * sizeof(*out_value))\r
136                 return -1;  /* RANGE */\r
137 \r
138         half = per_get_few_bits(pd, 31);\r
139         if(half < 0) return -1;\r
140 \r
141         if(uper_get_constrained_whole_number(pd, &lhalf, nbits - 31))\r
142                 return -1;\r
143 \r
144         *out_value = ((unsigned long)half << (nbits - 31)) | lhalf;\r
145         return 0;\r
146 }\r
147 \r
148 \r
149 /* X.691-2008/11, #11.5.6 -> #11.3 */\r
150 int\r
151 uper_put_constrained_whole_number_u(asn_per_outp_t *po, unsigned long v,\r
152                                     int nbits) {\r
153     if(nbits <= 31) {\r
154         return per_put_few_bits(po, v, nbits);\r
155     } else {\r
156         /* Put higher portion first, followed by lower 31-bit */\r
157         if(uper_put_constrained_whole_number_u(po, v >> 31, nbits - 31))\r
158             return -1;\r
159         return per_put_few_bits(po, v, 31);\r
160     }\r
161 }\r
162 \r
163 /*\r
164  * X.691 (08/2015) #11.9 "General rules for encoding a length determinant"\r
165  * Put the length "n" (or part of it) into the stream.\r
166  */\r
167 ssize_t\r
168 uper_put_length(asn_per_outp_t *po, size_t length, int *need_eom) {\r
169     int dummy = 0;\r
170     if(!need_eom) need_eom = &dummy;\r
171 \r
172     if(length <= 127) { /* #11.9.3.6 */\r
173         *need_eom = 0;\r
174         return per_put_few_bits(po, length, 8)\r
175             ? -1 : (ssize_t)length;\r
176     } else if(length < 16384) { /* #10.9.3.7 */\r
177         *need_eom = 0;\r
178         return per_put_few_bits(po, length|0x8000, 16)\r
179             ? -1 : (ssize_t)length;\r
180     }\r
181 \r
182     *need_eom = 0 == (length & 16383);\r
183     length >>= 14;\r
184     if(length > 4) {\r
185         *need_eom = 0;\r
186         length = 4;\r
187     }\r
188 \r
189     return per_put_few_bits(po, 0xC0 | length, 8)\r
190             ? -1 : (ssize_t)(length << 14);\r
191 \r
192 }\r
193 \r
194 \r
195 /*\r
196  * Put the normally small length "n" into the stream.\r
197  * This procedure used to encode length of extensions bit-maps\r
198  * for SET and SEQUENCE types.\r
199  */\r
200 int\r
201 uper_put_nslength(asn_per_outp_t *po, size_t length) {\r
202     if(length <= 64) {\r
203         /* #11.9.3.4 */\r
204         if(length == 0) return -1;\r
205         return per_put_few_bits(po, length - 1, 7) ? -1 : 0;\r
206     } else {\r
207         int need_eom = 0;\r
208         if(uper_put_length(po, length, &need_eom) != (ssize_t)length\r
209            || need_eom) {\r
210             /* This might happen in case of >16K extensions */\r
211             return -1;\r
212         }\r
213     }\r
214 \r
215     return 0;\r
216 }\r
217 \r
218 static int\r
219 per__long_range(long lb, long ub, unsigned long *range_r) {\r
220     unsigned long bounds_range;\r
221     if((ub < 0) == (lb < 0)) {\r
222         bounds_range = ub - lb;\r
223     } else if(lb < 0) {\r
224         assert(ub >= 0);\r
225         bounds_range = 1 + ((unsigned long)ub + (unsigned long)-(lb + 1));\r
226     } else {\r
227         assert(!"Unreachable");\r
228         return -1;\r
229     }\r
230     *range_r = bounds_range;\r
231     return 0;\r
232 }\r
233 \r
234 int\r
235 per_long_range_rebase(long v, long lb, long ub, unsigned long *output) {\r
236     unsigned long range;\r
237 \r
238     assert(lb <= ub);\r
239 \r
240     if(v < lb || v > ub || per__long_range(lb, ub, &range) < 0) {\r
241         /* Range error. */\r
242         return -1;\r
243     }\r
244 \r
245     /*\r
246      * Fundamentally what we're doing is returning (v-lb).\r
247      * However, this triggers undefined behavior when the word width\r
248      * of signed (v) is the same as the size of unsigned (*output).\r
249      * In practice, it triggers the UndefinedSanitizer. Therefore we shall\r
250      * compute the ranges accurately to avoid C's undefined behavior.\r
251      */\r
252     if((v < 0) == (lb < 0)) {\r
253         *output = v-lb;\r
254         return 0;\r
255     } else if(v < 0) {\r
256         unsigned long rebased = 1 + (unsigned long)-(v+1) + (unsigned long)lb;\r
257         assert(rebased <= range);   /* By construction */\r
258         *output = rebased;\r
259         return 0;\r
260     } else if(lb < 0) {\r
261         unsigned long rebased = 1 + (unsigned long)-(lb+1) + (unsigned long)v;\r
262         assert(rebased <= range);   /* By construction */\r
263         *output = rebased;\r
264         return 0;\r
265     } else {\r
266         assert(!"Unreachable");\r
267         return -1;\r
268     }\r
269 }\r
270 \r
271 int\r
272 per_long_range_unrebase(unsigned long inp, long lb, long ub, long *outp) {\r
273     unsigned long range;\r
274 \r
275     if(per__long_range(lb, ub, &range) != 0) {\r
276         return -1;\r
277     }\r
278 \r
279     if(inp > range) {\r
280         /*\r
281          * We can encode something in the given number of bits that technically\r
282          * exceeds the range. This is an avenue for security errors,\r
283          * so we don't allow that.\r
284          */\r
285         return -1;\r
286     }\r
287 \r
288     if(inp <= LONG_MAX) {\r
289         *outp = (long)inp + lb;\r
290     } else {\r
291         *outp = (lb + LONG_MAX + 1) + (long)((inp - LONG_MAX) - 1);\r
292     }\r
293 \r
294     return 0;\r
295 }\r
296 \r
297 int32_t\r
298 aper_get_align(asn_per_data_t *pd) {\r
299 \r
300         if(pd->nboff & 0x7) {\r
301                 ASN_DEBUG("Aligning %ld bits", 8 - ((unsigned long)pd->nboff & 0x7));\r
302                 return per_get_few_bits(pd, 8 - (pd->nboff & 0x7));\r
303         }\r
304         return 0;\r
305 }\r
306 \r
307 ssize_t\r
308 aper_get_length(asn_per_data_t *pd, int range, int ebits, int *repeat) {\r
309         ssize_t value;\r
310 \r
311         *repeat = 0;\r
312 \r
313         if (range <= 65536 && range >= 0)\r
314                 return aper_get_nsnnwn(pd, range);\r
315 \r
316         if (aper_get_align(pd) < 0)\r
317                 return -1;\r
318 \r
319         if(ebits >= 0) return per_get_few_bits(pd, ebits);\r
320 \r
321         value = per_get_few_bits(pd, 8);\r
322         if(value < 0) return -1;\r
323         if((value & 128) == 0)  /* #10.9.3.6 */\r
324                 return (value & 0x7F);\r
325         if((value & 64) == 0) { /* #10.9.3.7 */\r
326                 value = ((value & 63) << 8) | per_get_few_bits(pd, 8);\r
327                 if(value < 0) return -1;\r
328                 return value;\r
329         }\r
330         value &= 63;    /* this is "m" from X.691, #10.9.3.8 */\r
331         if(value < 1 || value > 4)\r
332                 return -1;\r
333         *repeat = 1;\r
334         return (16384 * value);\r
335 }\r
336 \r
337 ssize_t\r
338 aper_get_nslength(asn_per_data_t *pd) {\r
339         ssize_t length;\r
340 \r
341         ASN_DEBUG("Getting normally small length");\r
342 \r
343         if(per_get_few_bits(pd, 1) == 0) {\r
344                 length = per_get_few_bits(pd, 6) + 1;\r
345                 if(length <= 0) return -1;\r
346                 ASN_DEBUG("l=%ld", length);\r
347                 return length;\r
348         } else {\r
349                 int repeat;\r
350                 length = aper_get_length(pd, -1, -1, &repeat);\r
351                 if(length >= 0 && !repeat) return length;\r
352                 return -1; /* Error, or do not support >16K extensions */\r
353         }\r
354 }\r
355 \r
356 ssize_t\r
357 aper_get_nsnnwn(asn_per_data_t *pd, int range) {\r
358         ssize_t value;\r
359         int bytes = 0;\r
360 \r
361         ASN_DEBUG("getting nsnnwn with range %d", range);\r
362 \r
363         if(range <= 255) {\r
364                 int i;\r
365 \r
366                 if (range < 0) return -1;\r
367                 /* 1 -> 8 bits */\r
368                 for (i = 1; i <= 8; i++) {\r
369                         int upper = 1 << i;\r
370                         if (upper >= range)\r
371                                 break;\r
372                 }\r
373                 value = per_get_few_bits(pd, i);\r
374                 return value;\r
375         } else if (range == 256){\r
376                 /* 1 byte */\r
377                 bytes = 1;\r
378         } else if (range <= 65536) {\r
379                 /* 2 bytes */\r
380                 bytes = 2;\r
381         } else {\r
382                 return -1;\r
383         }\r
384         if (aper_get_align(pd) < 0)\r
385                 return -1;\r
386         value = per_get_few_bits(pd, 8 * bytes);\r
387         return value;\r
388 }\r
389 \r
390 int aper_put_align(asn_per_outp_t *po) {\r
391 \r
392         if(po->nboff & 0x7) {\r
393                 ASN_DEBUG("Aligning %ld bits", 8 - ((unsigned long)po->nboff & 0x7));\r
394                 if(per_put_few_bits(po, 0x00, (8 - (po->nboff & 0x7))))\r
395                         return -1;\r
396         }\r
397         return 0;\r
398 }\r
399 \r
400 ssize_t\r
401 aper_put_length(asn_per_outp_t *po, int range, size_t length) {\r
402 \r
403         ASN_DEBUG("APER put length %zu with range %d", length, range);\r
404 \r
405         /* 10.9 X.691 Note 2 */\r
406         if (range <= 65536 && range >= 0)\r
407                 return aper_put_nsnnwn(po, range, length);\r
408 \r
409         if (aper_put_align(po) < 0)\r
410                 return -1;\r
411 \r
412         if(length <= 127)          /* #10.9.3.6 */{\r
413                 return per_put_few_bits(po, length, 8)\r
414                 ? -1 : (ssize_t)length;\r
415         }\r
416         else if(length < 16384) /* #10.9.3.7 */\r
417                 return per_put_few_bits(po, length|0x8000, 16)\r
418                 ? -1 : (ssize_t)length;\r
419 \r
420         length >>= 14;\r
421         if(length > 4) length = 4;\r
422 \r
423         return per_put_few_bits(po, 0xC0 | length, 8)\r
424         ? -1 : (ssize_t)(length << 14);\r
425 }\r
426 \r
427 \r
428 int\r
429 aper_put_nslength(asn_per_outp_t *po, size_t length) {\r
430 \r
431         if(length <= 64) {\r
432                 /* #10.9.3.4 */\r
433                 if(length == 0) return -1;\r
434                 return per_put_few_bits(po, length-1, 7) ? -1 : 0;\r
435         } else {\r
436                 if(aper_put_length(po, -1, length) != (ssize_t)length) {\r
437                         /* This might happen in case of >16K extensions */\r
438                         return -1;\r
439                 }\r
440         }\r
441 \r
442         return 0;\r
443 }\r
444 \r
445 int\r
446 aper_put_nsnnwn(asn_per_outp_t *po, int range, int number) {\r
447         int bytes;\r
448 \r
449     ASN_DEBUG("aper put nsnnwn %d with range %d", number, range);\r
450         /* 10.5.7.1 X.691 */\r
451         if(range < 0) {\r
452                 int i;\r
453                 for (i = 1; ; i++) {\r
454                         int bits = 1 << (8 * i);\r
455                         if (number <= bits)\r
456                                 break;\r
457                 }\r
458                 bytes = i;\r
459                 assert(i <= 4);\r
460         }\r
461         if(range <= 255) {\r
462                 int i;\r
463                 for (i = 1; i <= 8; i++) {\r
464                         int bits = 1 << i;\r
465                         if (range <= bits)\r
466                                 break;\r
467                 }\r
468                 return per_put_few_bits(po, number, i);\r
469         } else if(range == 256) {\r
470                 bytes = 1;\r
471         } else if(range <= 65536) {\r
472                 bytes = 2;\r
473         } else { /* Ranges > 64K */\r
474                 int i;\r
475                 for (i = 1; ; i++) {\r
476                         int bits = 1 << (8 * i);\r
477                         if (range <= bits)\r
478                                 break;\r
479                 }\r
480                 assert(i <= 4);\r
481                 bytes = i;\r
482         }\r
483         if(aper_put_align(po) < 0) /* Aligning on octet */\r
484                 return -1;\r
485 /*      if(per_put_few_bits(po, bytes, 8))\r
486                 return -1;\r
487 */\r
488     return per_put_few_bits(po, number, 8 * bytes);\r
489 }\r