blob: e730d68b54330565108f04bc784db2a6cea24088 [file] [log] [blame]
Lev Walkined3a4ae2017-07-07 10:09:51 -07001/*
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#ifndef ASN_DISABLE_OER_SUPPORT
7
8#include <asn_internal.h>
9#include <INTEGER.h>
10#include <errno.h>
11
12asn_dec_rval_t
13INTEGER_decode_oer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
14 asn_oer_constraints_t *constraints, void **sptr,
15 const void *ptr, size_t size) {
16 asn_INTEGER_specifics_t *specs = (asn_INTEGER_specifics_t *)td->specifics;
17 asn_dec_rval_t rval = {RC_OK, 0};
18 INTEGER_t *st = (INTEGER_t *)*sptr;
19 asn_oer_constraint_t *ct;
Lev Walkine4d8c922017-07-10 20:29:33 -070020 size_t req_bytes = 0; /* 0 = length determinant is required */
Lev Walkined3a4ae2017-07-07 10:09:51 -070021
22 (void)opt_codec_ctx;
Lev Walkine4d8c922017-07-10 20:29:33 -070023 (void)specs;
Lev Walkined3a4ae2017-07-07 10:09:51 -070024
25 if(!st) {
26 st = (INTEGER_t *)(*sptr = CALLOC(1, sizeof(*st)));
27 if(!st) ASN__DECODE_FAILED;
28 }
29
Lev Walkined3a4ae2017-07-07 10:09:51 -070030 FREEMEM(st->buf);
31 st->buf = 0;
32 st->size = 0;
Lev Walkine4d8c922017-07-10 20:29:33 -070033
34 if(!constraints) constraints = td->oer_constraints;
35 ct = constraints ? &constraints->value : 0;
36
37 if(ct && (ct->flags & AOC_HAS_LOWER_BOUND) && ct->lower_bound >= 0) {
38 /* X.969 08/2015 10.2(a) */
39 unsigned msb; /* Most significant bit */
40 size_t useful_size;
41
42 intmax_t ub = ct->upper_bound;
43 if(ct->flags & AOC_HAS_UPPER_BOUND) {
44 if(ub <= 255) {
45 req_bytes = 1;
46 } else if(ub <= 65535) {
47 req_bytes = 2;
48 } else if(ub <= 4294967295UL) {
49 req_bytes = 4;
50 } else if(ub <= 18446744073709551615ULL) {
51 req_bytes = 8;
52 }
53 }
54
55 if(req_bytes == 0) { /* #8.6, using length determinant */
56 ssize_t consumed = oer_fetch_length(ptr, size, &req_bytes);
57 if(consumed == 0) {
58 ASN__DECODE_STARVED;
59 } else if(consumed == -1) {
60 ASN__DECODE_FAILED;
61 }
62 rval.consumed += consumed;
63 ptr = (const char *)ptr + consumed;
64 size -= consumed;
65 }
66
67 if(req_bytes > size) {
68 ASN__DECODE_STARVED;
69 }
70
71 /* Check most significant bit */
72 msb = *(const uint8_t *)ptr >> 7; /* yields 0 or 1 */
73 useful_size = msb + req_bytes;
74 st->buf = (uint8_t *)MALLOC(useful_size + 1);
75 if(!st->buf) {
76 ASN__DECODE_FAILED;
77 }
78
79 /*
80 * Record a large unsigned in a way not to confuse it
81 * with signed value.
82 */
83 st->buf[0] = '\0';
84 memcpy(st->buf + msb, ptr, req_bytes);
85 st->buf[useful_size] = '\0'; /* Just in case, 0-terminate */
86 st->size = useful_size;
87
88 rval.consumed += req_bytes;
89 return rval;
Lev Walkinfcfe19b2017-07-10 21:57:14 -070090 } else if(ct
91 && ((ct->flags
92 & (AOC_HAS_LOWER_BOUND | AOC_HAS_UPPER_BOUND))
93 == (AOC_HAS_LOWER_BOUND | AOC_HAS_UPPER_BOUND))) {
Lev Walkine4d8c922017-07-10 20:29:33 -070094 /* X.969 08/2015 10.2(b) - no lower bound or negative lower bound */
95
96 intmax_t lb = ct->lower_bound;
97 intmax_t ub = ct->upper_bound;
98
Lev Walkinfcfe19b2017-07-10 21:57:14 -070099 if(lb >= -128 && ub <= 127) {
100 req_bytes = 1;
101 } else if(lb >= -32768 && ub <= 32767) {
102 req_bytes = 2;
103 } else if(lb >= -2147483648L && ub <= 2147483647L) {
104 req_bytes = 4;
105 } else if(lb >= -9223372036854775808LL && ub <= 9223372036854775807LL) {
106 req_bytes = 8;
Lev Walkine4d8c922017-07-10 20:29:33 -0700107 }
108 }
109
110 /* No lower bound and no upper bound, effectively */
111
112 if(req_bytes == 0) { /* #8.6, using length determinant */
113 ssize_t consumed = oer_fetch_length(ptr, size, &req_bytes);
114 if(consumed == 0) {
115 ASN__DECODE_STARVED;
116 } else if(consumed == -1) {
117 ASN__DECODE_FAILED;
118 }
119 rval.consumed += consumed;
120 ptr = (const char *)ptr + consumed;
121 size -= consumed;
122 }
123
124 if(req_bytes > size) {
125 ASN__DECODE_STARVED;
126 }
127
128 st->buf = (uint8_t *)MALLOC(req_bytes + 1);
129 if(!st->buf) {
130 ASN__DECODE_FAILED;
131 }
132
133 memcpy(st->buf, ptr, req_bytes);
134 st->buf[req_bytes] = '\0'; /* Just in case, 0-terminate */
135 st->size = req_bytes;
136
137 rval.consumed += req_bytes;
138 return rval;
Lev Walkined3a4ae2017-07-07 10:09:51 -0700139}
140
Lev Walkinfcfe19b2017-07-10 21:57:14 -0700141/*
142 * Encode as Canonical OER.
143 */
144asn_enc_rval_t
145INTEGER_encode_oer(asn_TYPE_descriptor_t *td,
146 asn_oer_constraints_t *constraints, void *sptr,
147 asn_app_consume_bytes_f *cb, void *app_key) {
Lev Walkincc9b3ae2017-07-14 08:57:02 +0400148 const INTEGER_t *st = sptr;
Lev Walkinfcfe19b2017-07-10 21:57:14 -0700149 asn_enc_rval_t er;
150 asn_oer_constraint_t *ct;
151 const uint8_t *buf;
152 const uint8_t *end;
153 size_t useful_bytes;
154 size_t req_bytes = 0;
155 int encode_as_unsigned;
156 int sign = 0;
157
158 if(!st || st->size == 0) ASN__ENCODE_FAILED;
159
160 if(!constraints) constraints = td->oer_constraints;
161 ct = constraints ? &constraints->value : 0;
162
163 er.encoded = 0;
164
165 buf = st->buf;
166 end = buf + st->size;
167
168 encode_as_unsigned =
169 ct && (ct->flags & AOC_HAS_LOWER_BOUND) && ct->lower_bound >= 0;
170
171 sign = (buf && buf < end) ? buf[0] & 0x80 : 0;
172
Lev Walkinfcfe19b2017-07-10 21:57:14 -0700173 /* Ignore 9 leading zeroes or ones */
Lev Walkincc9b3ae2017-07-14 08:57:02 +0400174 if(encode_as_unsigned) {
175 if(sign) {
176 /* The value given is a signed value. Can't proceed. */
177 ASN__ENCODE_FAILED;
Lev Walkinfcfe19b2017-07-10 21:57:14 -0700178 }
Lev Walkincc9b3ae2017-07-14 08:57:02 +0400179 /* Remove leading zeros. */
180 for(; buf + 1 < end; buf++) {
181 if(buf[0] != 0x0) break;
182 }
183 } else {
184 for(; buf + 1 < end; buf++) {
185 if(buf[0] == 0x0 && (buf[1] & 0x80) == 0) {
186 continue;
187 } else if(buf[0] == 0xff && (buf[1] & 0x80) != 0) {
188 continue;
189 }
190 break;
191 }
Lev Walkinfcfe19b2017-07-10 21:57:14 -0700192 }
193
194 useful_bytes = end - buf;
195 if(encode_as_unsigned) {
196 intmax_t ub = ct->upper_bound;
197
198 if(ub <= 255) {
199 req_bytes = 1;
200 } else if(ub <= 65535) {
201 req_bytes = 2;
202 } else if(ub <= 4294967295UL) {
203 req_bytes = 4;
204 } else if(ub <= 18446744073709551615ULL) {
205 req_bytes = 8;
206 }
207 } else if(ct
208 && ((ct->flags
209 & (AOC_HAS_LOWER_BOUND | AOC_HAS_UPPER_BOUND))
210 == (AOC_HAS_LOWER_BOUND | AOC_HAS_UPPER_BOUND))) {
211 /* X.969 08/2015 10.2(b) - no lower bound or negative lower bound */
212
213 intmax_t lb = ct->lower_bound;
214 intmax_t ub = ct->upper_bound;
215
216 if(lb >= -128 && ub <= 127) {
217 req_bytes = 1;
218 } else if(lb >= -32768 && ub <= 32767) {
219 req_bytes = 2;
220 } else if(lb >= -2147483648L && ub <= 2147483647L) {
221 req_bytes = 4;
222 } else if(lb >= -9223372036854775808LL && ub <= 9223372036854775807LL) {
223 req_bytes = 8;
224 }
225 }
226
227 if(req_bytes == 0) {
228 ssize_t r = oer_serialize_length(useful_bytes, cb, app_key);
229 if(r < 0) {
230 ASN__ENCODE_FAILED;
231 }
232 er.encoded += r;
233 req_bytes = useful_bytes;
234 } else if(req_bytes < useful_bytes) {
235 ASN__ENCODE_FAILED;
236 }
237
238 er.encoded += req_bytes;
239
240 for(; req_bytes > useful_bytes; req_bytes--) {
241 if(cb(sign?"\xff":"\0", 1, app_key) < 0) {
242 ASN__ENCODE_FAILED;
243 }
244 }
245
246 if(cb(buf, useful_bytes, app_key) < 0) {
247 ASN__ENCODE_FAILED;
248 }
249
250 ASN__ENCODED_OK(er);
251}
252
Lev Walkined3a4ae2017-07-07 10:09:51 -0700253#endif /* ASN_DISABLE_OER_SUPPORT */