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