2 * Copyright (c) 2017 Lev Walkin <vlm@lionet.info>.
4 * Redistribution and modifications are permitted subject to BSD license.
6 #include <asn_internal.h>
7 #include <BIT_STRING.h>
10 #define RETURN(_code) \
12 asn_dec_rval_t tmprval; \
13 tmprval.code = _code; \
14 tmprval.consumed = consumed_myself; \
18 static asn_per_constraint_t asn_DEF_BIT_STRING_constraint_size = {
19 APC_SEMI_CONSTRAINED, -1, -1, 0, 0};
22 BIT_STRING_decode_uper(const asn_codec_ctx_t *opt_codec_ctx,
23 const asn_TYPE_descriptor_t *td,
24 const asn_per_constraints_t *constraints, void **sptr,
26 const asn_OCTET_STRING_specifics_t *specs = td->specifics
27 ? (const asn_OCTET_STRING_specifics_t *)td->specifics
28 : &asn_SPC_BIT_STRING_specs;
29 const asn_per_constraints_t *pc =
30 constraints ? constraints : td->encoding_constraints.per_constraints;
31 const asn_per_constraint_t *csiz;
32 asn_dec_rval_t rval = { RC_OK, 0 };
33 BIT_STRING_t *st = (BIT_STRING_t *)*sptr;
34 ssize_t consumed_myself = 0;
42 csiz = &asn_DEF_BIT_STRING_constraint_size;
45 if(specs->subvariant != ASN_OSUBV_BIT) {
46 ASN_DEBUG("Subvariant %d is not BIT OSUBV_BIT", specs->subvariant);
51 * Allocate the string.
54 st = (BIT_STRING_t *)(*sptr = CALLOC(1, specs->struct_size));
55 if(!st) RETURN(RC_FAIL);
58 ASN_DEBUG("PER Decoding %s size %ld .. %ld bits %d",
59 csiz->flags & APC_EXTENSIBLE ? "extensible" : "non-extensible",
60 csiz->lower_bound, csiz->upper_bound, csiz->effective_bits);
62 if(csiz->flags & APC_EXTENSIBLE) {
63 int inext = per_get_few_bits(pd, 1);
64 if(inext < 0) RETURN(RC_WMORE);
66 csiz = &asn_DEF_BIT_STRING_constraint_size;
70 if(csiz->effective_bits >= 0) {
72 st->size = (csiz->upper_bound + 7) >> 3;
73 st->buf = (uint8_t *)MALLOC(st->size + 1);
74 if(!st->buf) { st->size = 0; RETURN(RC_FAIL); }
77 /* X.691, #16.5: zero-length encoding */
78 /* X.691, #16.6: short fixed length encoding (up to 2 octets) */
79 /* X.691, #16.7: long fixed length encoding (up to 64K octets) */
80 if(csiz->effective_bits == 0) {
82 ASN_DEBUG("Encoding BIT STRING size %ld", csiz->upper_bound);
83 ret = per_get_many_bits(pd, st->buf, 0, csiz->upper_bound);
84 if(ret < 0) RETURN(RC_WMORE);
85 consumed_myself += csiz->upper_bound;
86 st->buf[st->size] = 0;
87 st->bits_unused = (8 - (csiz->upper_bound & 0x7)) & 0x7;
99 /* Get the PER length */
100 raw_len = uper_get_length(pd, csiz->effective_bits, csiz->lower_bound,
102 if(raw_len < 0) RETURN(RC_WMORE);
103 if(raw_len == 0 && st->buf) break;
105 ASN_DEBUG("Got PER length eb %ld, len %ld, %s (%s)",
106 (long)csiz->effective_bits, (long)raw_len,
107 repeat ? "repeat" : "once", td->name);
109 len_bytes = (len_bits + 7) >> 3;
110 if(len_bits & 0x7) st->bits_unused = 8 - (len_bits & 0x7);
111 /* len_bits be multiple of 16K if repeat is set */
112 p = REALLOC(st->buf, st->size + len_bytes + 1);
113 if(!p) RETURN(RC_FAIL);
114 st->buf = (uint8_t *)p;
116 ret = per_get_many_bits(pd, &st->buf[st->size], 0, len_bits);
117 if(ret < 0) RETURN(RC_WMORE);
118 st->size += len_bytes;
120 st->buf[st->size] = 0; /* nul-terminate */
126 BIT_STRING_encode_uper(const asn_TYPE_descriptor_t *td,
127 const asn_per_constraints_t *constraints,
128 const void *sptr, asn_per_outp_t *po) {
129 const asn_OCTET_STRING_specifics_t *specs =
130 td->specifics ? (const asn_OCTET_STRING_specifics_t *)td->specifics
131 : &asn_SPC_BIT_STRING_specs;
132 const asn_per_constraints_t *pc =
133 constraints ? constraints : td->encoding_constraints.per_constraints;
134 const asn_per_constraint_t *csiz;
135 const BIT_STRING_t *st = (const BIT_STRING_t *)sptr;
136 BIT_STRING_t compact_bstr; /* Do not modify this directly! */
137 asn_enc_rval_t er = { 0, 0, 0 };
138 int inext = 0; /* Lies not within extension root */
144 if(!st || (!st->buf && st->size))
147 if(specs->subvariant == ASN_OSUBV_BIT) {
148 if((st->size == 0 && st->bits_unused) || (st->bits_unused & ~7))
157 csiz = &asn_DEF_BIT_STRING_constraint_size;
159 ct_extensible = csiz->flags & APC_EXTENSIBLE;
161 /* Figure out the size without the trailing bits */
162 st = BIT_STRING__compactify(st, &compact_bstr);
163 size_in_bits = 8 * st->size - st->bits_unused;
166 "Encoding %s into %" ASN_PRI_SIZE " bits"
167 " (%ld..%ld, effective %d)%s",
168 td->name, size_in_bits, csiz->lower_bound, csiz->upper_bound,
169 csiz->effective_bits, ct_extensible ? " EXT" : "");
171 /* Figure out whether size lies within PER visible constraint */
173 if(csiz->effective_bits >= 0) {
174 if((ssize_t)size_in_bits > csiz->upper_bound) {
176 csiz = &asn_DEF_BIT_STRING_constraint_size;
187 /* Declare whether length is [not] within extension root */
188 if(per_put_few_bits(po, inext, 1))
192 if(csiz->effective_bits >= 0 && !inext) {
193 int add_trailer = (ssize_t)size_in_bits < csiz->lower_bound;
195 "Encoding %" ASN_PRI_SIZE " bytes (%ld), length (in %d bits) trailer %d; actual "
196 "value %" ASN_PRI_SSIZE "",
197 st->size, size_in_bits - csiz->lower_bound, csiz->effective_bits,
199 add_trailer ? 0 : (ssize_t)size_in_bits - csiz->lower_bound);
200 ret = per_put_few_bits(
201 po, add_trailer ? 0 : (ssize_t)size_in_bits - csiz->lower_bound,
202 csiz->effective_bits);
203 if(ret) ASN__ENCODE_FAILED;
204 ret = per_put_many_bits(po, st->buf, size_in_bits);
205 if(ret) ASN__ENCODE_FAILED;
207 static const uint8_t zeros[16];
208 size_t trailing_zero_bits = csiz->lower_bound - size_in_bits;
209 while(trailing_zero_bits > 0) {
210 if(trailing_zero_bits > 8 * sizeof(zeros)) {
211 ret = per_put_many_bits(po, zeros, 8 * sizeof(zeros));
212 trailing_zero_bits -= 8 * sizeof(zeros);
214 ret = per_put_many_bits(po, zeros, trailing_zero_bits);
215 trailing_zero_bits = 0;
217 if(ret) ASN__ENCODE_FAILED;
223 ASN_DEBUG("Encoding %" ASN_PRI_SIZE " bytes", st->size);
228 ssize_t maySave = uper_put_length(po, size_in_bits, &need_eom);
229 if(maySave < 0) ASN__ENCODE_FAILED;
231 ASN_DEBUG("Encoding %" ASN_PRI_SSIZE " of %" ASN_PRI_SIZE "", maySave, size_in_bits);
233 ret = per_put_many_bits(po, buf, maySave);
234 if(ret) ASN__ENCODE_FAILED;
237 size_in_bits -= maySave;
238 assert(!(maySave & 0x07) || !size_in_bits);
239 if(need_eom && uper_put_length(po, 0, 0))
240 ASN__ENCODE_FAILED; /* End of Message length */
241 } while(size_in_bits);