Change version after creation of r2 branch
[ric-plt/resource-status-manager.git] / RSM / 3rdparty / asn1codec / e2ap_engine / ber_tlv_length.c
1
2 /*-
3  * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
4  * Redistribution and modifications are permitted subject to BSD license.
5  */
6 #include <asn_internal.h>
7 #include <ber_tlv_length.h>
8 #include <ber_tlv_tag.h>
9
10 ssize_t
11 ber_fetch_length(int _is_constructed, const void *bufptr, size_t size,
12                 ber_tlv_len_t *len_r) {
13         const uint8_t *buf = (const uint8_t *)bufptr;
14         unsigned oct;
15
16         if(size == 0)
17                 return 0;       /* Want more */
18
19         oct = *(const uint8_t *)buf;
20         if((oct & 0x80) == 0) {
21                 /*
22                  * Short definite length.
23                  */
24                 *len_r = oct;   /* & 0x7F */
25                 return 1;
26         } else {
27                 ber_tlv_len_t len;
28                 size_t skipped;
29
30                 if(_is_constructed && oct == 0x80) {
31                         *len_r = -1;    /* Indefinite length */
32                         return 1;
33                 }
34
35                 if(oct == 0xff) {
36                         /* Reserved in standard for future use. */
37                         return -1;
38                 }
39
40                 oct &= 0x7F;    /* Leave only the 7 LS bits */
41                 for(len = 0, buf++, skipped = 1;
42                         oct && (++skipped <= size); buf++, oct--) {
43
44                         /* Verify that we won't overflow. */
45                         if(!(len >> ((8 * sizeof(len)) - (8+1)))) {
46                                 len = (len << 8) | *buf;
47                         } else {
48                                 /* Too large length value. */
49                                 return -1;
50                         }
51                 }
52
53                 if(oct == 0) {
54                         if(len < 0 || len > RSSIZE_MAX) {
55                                 /* Length value out of sane range. */
56                                 return -1;
57                         }
58
59                         *len_r = len;
60                         return skipped;
61                 }
62
63                 return 0;       /* Want more */
64         }
65
66 }
67
68 ssize_t
69 ber_skip_length(const asn_codec_ctx_t *opt_codec_ctx,
70                 int _is_constructed, const void *ptr, size_t size) {
71         ber_tlv_len_t vlen;     /* Length of V in TLV */
72         ssize_t tl;             /* Length of L in TLV */
73         ssize_t ll;             /* Length of L in TLV */
74         size_t skip;
75
76         /*
77          * Make sure we didn't exceed the maximum stack size.
78          */
79         if(ASN__STACK_OVERFLOW_CHECK(opt_codec_ctx))
80                 return -1;
81
82         /*
83          * Determine the size of L in TLV.
84          */
85         ll = ber_fetch_length(_is_constructed, ptr, size, &vlen);
86         if(ll <= 0) return ll;
87
88         /*
89          * Definite length.
90          */
91         if(vlen >= 0) {
92                 skip = ll + vlen;
93                 if(skip > size)
94                         return 0;       /* Want more */
95                 return skip;
96         }
97
98         /*
99          * Indefinite length!
100          */
101         ASN_DEBUG("Skipping indefinite length");
102         for(skip = ll, ptr = ((const char *)ptr) + ll, size -= ll;;) {
103                 ber_tlv_tag_t tag;
104
105                 /* Fetch the tag */
106                 tl = ber_fetch_tag(ptr, size, &tag);
107                 if(tl <= 0) return tl;
108
109                 ll = ber_skip_length(opt_codec_ctx,
110                         BER_TLV_CONSTRUCTED(ptr),
111                         ((const char *)ptr) + tl, size - tl);
112                 if(ll <= 0) return ll;
113
114                 skip += tl + ll;
115
116                 /*
117                  * This may be the end of the indefinite length structure,
118                  * two consecutive 0 octets.
119                  * Check if it is true.
120                  */
121                 if(((const uint8_t *)ptr)[0] == 0
122                 && ((const uint8_t *)ptr)[1] == 0)
123                         return skip;
124
125                 ptr = ((const char *)ptr) + tl + ll;
126                 size -= tl + ll;
127         }
128
129         /* UNREACHABLE */
130 }
131
132 size_t
133 der_tlv_length_serialize(ber_tlv_len_t len, void *bufp, size_t size) {
134         size_t required_size;   /* Size of len encoding */
135         uint8_t *buf = (uint8_t *)bufp;
136         uint8_t *end;
137         int i;
138
139         if(len <= 127) {
140                 /* Encoded in 1 octet */
141                 if(size) *buf = (uint8_t)len;
142                 return 1;
143         }
144
145         /*
146          * Compute the size of the subsequent bytes.
147          */
148         for(required_size = 1, i = 8; i < 8 * (int)sizeof(len); i += 8) {
149                 if(len >> i)
150                         required_size++;
151                 else
152                         break;
153         }
154
155         if(size <= required_size)
156                 return required_size + 1;
157
158         *buf++ = (uint8_t)(0x80 | required_size);  /* Length of the encoding */
159
160         /*
161          * Produce the len encoding, space permitting.
162          */
163         end = buf + required_size;
164         for(i -= 8; buf < end; i -= 8, buf++)
165                 *buf = (uint8_t)(len >> i);
166
167         return required_size + 1;
168 }
169