Enhanced SIM for E2AP v1 for TS UC
[sim/e2-interface.git] / e2sim / e2apv1sim / ASN1c / oer_support.c
1 /*
2  * Copyright (c) 2017 Lev Walkin <vlm@lionet.info>.
3  * All rights reserved.
4  * Redistribution and modifications are permitted subject to BSD license.
5  */
6 #include <asn_system.h>
7 #include <asn_internal.h>
8
9 #include <oer_support.h>
10
11 /*
12  * Fetch the length determinant (X.696 08/2015, #8.6) into *len_r.
13  * RETURN VALUES:
14  *       0:     More data expected than bufptr contains.
15  *      -1:     Fatal error deciphering length.
16  *      >0:     Number of bytes used from bufptr.
17  */
18 ssize_t
19 oer_fetch_length(const void *bufptr, size_t size, size_t *len_r) {
20     uint8_t first_byte;
21     size_t len_len;    /* Length of the length determinant */
22     const uint8_t *b;
23     const uint8_t *bend;
24     size_t len;
25
26     if(size == 0) {
27         *len_r = 0;
28         return 0;
29     }
30
31     first_byte = *(const uint8_t *)bufptr;
32     if((first_byte & 0x80) == 0) {   /* Short form */
33         *len_r = first_byte; /* 0..127 */
34         return 1;
35     }
36
37     len_len = (first_byte & 0x7f);
38     if((1 + len_len) > size) {
39         *len_r = 0;
40         return 0;
41     }
42
43     b = (const uint8_t *)bufptr + 1;
44     bend = b + len_len;
45
46     for(; b < bend && *b == 0; b++) {
47         /* Skip the leading 0-bytes */
48     }
49
50     if((bend - b) > (ssize_t)sizeof(size_t)) {
51         /* Length is not representable by the native size_t type */
52         *len_r = 0;
53         return -1;
54     }
55
56     for(len = 0; b < bend; b++) {
57         len = (len << 8) + *b;
58     }
59
60     if(len > RSIZE_MAX) { /* A bit of C11 validation */
61         *len_r = 0;
62         return -1;
63     }
64
65     *len_r = len;
66     assert(len_len + 1 == (size_t)(bend - (const uint8_t *)bufptr));
67     return len_len + 1;
68 }
69
70
71 /*
72  * Serialize OER length. Returns the number of bytes serialized
73  * or -1 if a given callback returned with negative result.
74  */
75 ssize_t
76 oer_serialize_length(size_t length, asn_app_consume_bytes_f *cb,
77                      void *app_key) {
78     uint8_t scratch[1 + sizeof(length)];
79     uint8_t *sp = scratch;
80     int littleEndian = 1;   /* Run-time detection */
81     const uint8_t *pstart;
82     const uint8_t *pend;
83     const uint8_t *p;
84     int add;
85
86     if(length <= 127) {
87         uint8_t b = length;
88         if(cb(&b, 1, app_key) < 0) {
89             return -1;
90         }
91         return 1;
92     }
93
94     if(*(char *)&littleEndian) {
95         pstart = (const uint8_t *)&length + sizeof(length) - 1;
96         pend = (const uint8_t *)&length;
97         add = -1;
98     } else {
99         pstart = (const uint8_t *)&length;
100         pend = pstart + sizeof(length);
101         add = 1;
102     }
103
104     for(p = pstart; p != pend; p += add) {
105         /* Skip leading zeros. */
106         if(*p) break;
107     }
108
109     for(sp = scratch + 1; ; p += add) {
110         *sp++ = *p;
111         if(p == pend) break;
112     }
113     assert((sp - scratch) - 1 <= 0x7f);
114     scratch[0] = 0x80 + ((sp - scratch) - 1);
115
116     if(cb(scratch, sp - scratch, app_key) < 0) {
117         return -1;
118     }
119
120     return sp - scratch;
121 }
122