]> git.stg.codes - stg.git/blob - libs/smux/INTEGER_oer.c
Update README.
[stg.git] / libs / smux / INTEGER_oer.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 #ifndef ASN_DISABLE_OER_SUPPORT
7
8 #include <asn_internal.h>
9 #include <INTEGER.h>
10 #include <errno.h>
11
12 asn_dec_rval_t
13 INTEGER_decode_oer(const asn_codec_ctx_t *opt_codec_ctx,
14                    const asn_TYPE_descriptor_t *td,
15                    const asn_oer_constraints_t *constraints, void **sptr,
16                    const void *ptr, size_t size) {
17     const asn_INTEGER_specifics_t *specs =
18         (const asn_INTEGER_specifics_t *)td->specifics;
19     asn_dec_rval_t rval = {RC_OK, 0};
20     INTEGER_t *st = (INTEGER_t *)*sptr;
21     struct asn_oer_constraint_number_s ct = {0, 0};
22     size_t req_bytes;
23
24     (void)opt_codec_ctx;
25     (void)specs;
26
27     if(!st) {
28         st = (INTEGER_t *)(*sptr = CALLOC(1, sizeof(*st)));
29         if(!st) ASN__DECODE_FAILED;
30     }
31
32     FREEMEM(st->buf);
33     st->buf = 0;
34     st->size = 0;
35
36     if(!constraints) constraints = td->encoding_constraints.oer_constraints;
37     if(constraints) ct = constraints->value;
38
39     if(ct.width) {
40         req_bytes = ct.width;
41     } else {
42         /* No lower bound and no upper bound, effectively */
43
44         ssize_t consumed = oer_fetch_length(ptr, size, &req_bytes);
45         if(consumed == 0) {
46             ASN__DECODE_STARVED;
47         } else if(consumed == -1) {
48             ASN__DECODE_FAILED;
49         }
50         rval.consumed += consumed;
51         ptr = (const char *)ptr + consumed;
52         size -= consumed;
53     }
54
55     if(req_bytes > size) {
56         ASN__DECODE_STARVED;
57     }
58
59     if(ct.positive) {
60         /* X.969 08/2015 10.2(a) */
61         unsigned msb;   /* Most significant bit */
62         size_t useful_size;
63
64         /* Check most significant bit */
65         msb = *(const uint8_t *)ptr >> 7; /* yields 0 or 1 */
66         useful_size = msb + req_bytes;
67         st->buf = (uint8_t *)MALLOC(useful_size + 1);
68         if(!st->buf) {
69             ASN__DECODE_FAILED;
70         }
71
72         /*
73          * Record a large unsigned in a way not to confuse it
74          * with signed value.
75          */
76         st->buf[0] = '\0';
77         memcpy(st->buf + msb, ptr, req_bytes);
78         st->buf[useful_size] = '\0';    /* Just in case, 0-terminate */
79         st->size = useful_size;
80
81         rval.consumed += req_bytes;
82         return rval;
83     } else {
84         /* X.969 08/2015 10.2(b) */
85         st->buf = (uint8_t *)MALLOC(req_bytes + 1);
86         if(!st->buf) {
87             ASN__DECODE_FAILED;
88         }
89
90         memcpy(st->buf, ptr, req_bytes);
91         st->buf[req_bytes] = '\0'; /* Just in case, 0-terminate */
92         st->size = req_bytes;
93
94         rval.consumed += req_bytes;
95         return rval;
96     }
97 }
98
99 /*
100  * Encode as Canonical OER.
101  */
102 asn_enc_rval_t
103 INTEGER_encode_oer(const asn_TYPE_descriptor_t *td,
104                    const asn_oer_constraints_t *constraints, const void *sptr,
105                    asn_app_consume_bytes_f *cb, void *app_key) {
106     const INTEGER_t *st = sptr;
107     asn_enc_rval_t er;
108     struct asn_oer_constraint_number_s ct = {0, 0};
109     const uint8_t *buf;
110     const uint8_t *end;
111     size_t useful_bytes;
112     size_t req_bytes = 0;
113     int sign = 0;
114
115     if(!st || st->size == 0) ASN__ENCODE_FAILED;
116
117     if(!constraints) constraints = td->encoding_constraints.oer_constraints;
118     if(constraints) ct = constraints->value;
119
120     er.encoded = 0;
121
122     buf = st->buf;
123     end = buf + st->size;
124
125     sign = (buf && buf < end) ? buf[0] & 0x80 : 0;
126
127     /* Ignore 9 leading zeroes or ones */
128     if(ct.positive) {
129         if(sign) {
130             /* The value given is a signed value. Can't proceed. */
131             ASN__ENCODE_FAILED;
132         }
133         /* Remove leading zeros. */
134         for(; buf + 1 < end; buf++) {
135             if(buf[0] != 0x0) break;
136         }
137     } else {
138         for(; buf + 1 < end; buf++) {
139             if(buf[0] == 0x0 && (buf[1] & 0x80) == 0) {
140                 continue;
141             } else if(buf[0] == 0xff && (buf[1] & 0x80) != 0) {
142                 continue;
143             }
144             break;
145         }
146     }
147
148     useful_bytes = end - buf;
149     if(ct.width) {
150         req_bytes = ct.width;
151     } else {
152         ssize_t r = oer_serialize_length(useful_bytes, cb, app_key);
153         if(r < 0) {
154             ASN__ENCODE_FAILED;
155         }
156         er.encoded += r;
157         req_bytes = useful_bytes;
158     }
159
160     if(req_bytes < useful_bytes) {
161         ASN__ENCODE_FAILED;
162     }
163
164     er.encoded += req_bytes;
165
166     for(; req_bytes > useful_bytes; req_bytes--) {
167         if(cb(sign?"\xff":"\0", 1, app_key) < 0) {
168             ASN__ENCODE_FAILED;
169         }
170     }
171
172     if(cb(buf, useful_bytes, app_key) < 0) {
173         ASN__ENCODE_FAILED;
174     }
175
176     ASN__ENCODED_OK(er);
177 }
178
179 #endif  /* ASN_DISABLE_OER_SUPPORT */