blob: f2dd1c60785ef234407feae46a8e2475d580531a [file] [log] [blame]
Lev Walkinf15320b2004-06-03 03:38:44 +00001/*-
Lev Walkin75b1bef2005-04-25 19:38:21 +00002 * Copyright (c) 2003, 2004, 2005 Lev Walkin <vlm@lionet.info>.
3 * All rights reserved.
Lev Walkinf15320b2004-06-03 03:38:44 +00004 * Redistribution and modifications are permitted subject to BSD license.
5 */
Lev Walkina9cc46e2004-09-22 16:06:28 +00006#include <asn_internal.h>
Lev Walkinf15320b2004-06-03 03:38:44 +00007#include <OCTET_STRING.h>
Lev Walkinbbd93252004-10-12 05:57:23 +00008#include <BIT_STRING.h> /* for .bits_unused member */
Lev Walkinf15320b2004-06-03 03:38:44 +00009#include <errno.h>
10
11/*
12 * OCTET STRING basic type description.
13 */
Lev Walkinde4825d2004-09-29 13:20:14 +000014static ber_tlv_tag_t asn_DEF_OCTET_STRING_tags[] = {
Lev Walkinf15320b2004-06-03 03:38:44 +000015 (ASN_TAG_CLASS_UNIVERSAL | (4 << 2))
16};
Lev Walkinbbd93252004-10-12 05:57:23 +000017static asn_OCTET_STRING_specifics_t asn_DEF_OCTET_STRING_specs = {
18 sizeof(OCTET_STRING_t),
19 offsetof(OCTET_STRING_t, _asn_ctx),
20 0
21};
Lev Walkin59b176e2005-11-26 11:25:14 +000022static asn_per_constraint_t asn_DEF_OCTET_STRING_constraint = {
Lev Walkince676dd2005-12-20 22:34:55 +000023 APC_SEMI_CONSTRAINED, -1, -1, 0, 0
Lev Walkin59b176e2005-11-26 11:25:14 +000024};
Lev Walkinde4825d2004-09-29 13:20:14 +000025asn_TYPE_descriptor_t asn_DEF_OCTET_STRING = {
Lev Walkindc06f6b2004-10-20 15:50:55 +000026 "OCTET STRING", /* Canonical name */
27 "OCTET_STRING", /* XML tag name */
Lev Walkina9cc46e2004-09-22 16:06:28 +000028 OCTET_STRING_free,
29 OCTET_STRING_print, /* non-ascii stuff, generally */
Lev Walkinf15320b2004-06-03 03:38:44 +000030 asn_generic_no_constraint,
31 OCTET_STRING_decode_ber,
32 OCTET_STRING_encode_der,
Lev Walkindc06f6b2004-10-20 15:50:55 +000033 OCTET_STRING_decode_xer_hex,
Lev Walkina9cc46e2004-09-22 16:06:28 +000034 OCTET_STRING_encode_xer,
Lev Walkin59b176e2005-11-26 11:25:14 +000035 OCTET_STRING_decode_uper, /* Unaligned PER decoder */
Lev Walkin523de9e2006-08-18 01:34:18 +000036 OCTET_STRING_encode_uper, /* Unaligned PER encoder */
Lev Walkinf15320b2004-06-03 03:38:44 +000037 0, /* Use generic outmost tag fetcher */
Lev Walkinde4825d2004-09-29 13:20:14 +000038 asn_DEF_OCTET_STRING_tags,
39 sizeof(asn_DEF_OCTET_STRING_tags)
40 / sizeof(asn_DEF_OCTET_STRING_tags[0]),
41 asn_DEF_OCTET_STRING_tags, /* Same as above */
42 sizeof(asn_DEF_OCTET_STRING_tags)
43 / sizeof(asn_DEF_OCTET_STRING_tags[0]),
Lev Walkin59b176e2005-11-26 11:25:14 +000044 0, /* No PER visible constraints */
Lev Walkin449f8322004-08-20 13:23:42 +000045 0, 0, /* No members */
Lev Walkinbbd93252004-10-12 05:57:23 +000046 &asn_DEF_OCTET_STRING_specs
Lev Walkinf15320b2004-06-03 03:38:44 +000047};
48
Lev Walkincc6a9102004-09-23 22:06:26 +000049#undef _CH_PHASE
50#undef NEXT_PHASE
51#undef PREV_PHASE
Lev Walkin75b1bef2005-04-25 19:38:21 +000052#define _CH_PHASE(ctx, inc) do { \
53 if(ctx->phase == 0) \
54 ctx->context = 0; \
55 ctx->phase += inc; \
Lev Walkinf15320b2004-06-03 03:38:44 +000056 } while(0)
57#define NEXT_PHASE(ctx) _CH_PHASE(ctx, +1)
58#define PREV_PHASE(ctx) _CH_PHASE(ctx, -1)
59
Lev Walkincc6a9102004-09-23 22:06:26 +000060#undef ADVANCE
Lev Walkin75b1bef2005-04-25 19:38:21 +000061#define ADVANCE(num_bytes) do { \
62 size_t num = (num_bytes); \
63 buf_ptr = ((const char *)buf_ptr) + num; \
64 size -= num; \
65 consumed_myself += num; \
Lev Walkinf15320b2004-06-03 03:38:44 +000066 } while(0)
67
Lev Walkincc6a9102004-09-23 22:06:26 +000068#undef RETURN
Lev Walkin75b1bef2005-04-25 19:38:21 +000069#define RETURN(_code) do { \
Lev Walkin59b176e2005-11-26 11:25:14 +000070 asn_dec_rval_t tmprval; \
71 tmprval.code = _code; \
72 tmprval.consumed = consumed_myself; \
73 return tmprval; \
Lev Walkinf15320b2004-06-03 03:38:44 +000074 } while(0)
75
Lev Walkincc6a9102004-09-23 22:06:26 +000076#undef APPEND
Lev Walkind9bd7752004-06-05 08:17:50 +000077#define APPEND(bufptr, bufsize) do { \
Lev Walkin75b1bef2005-04-25 19:38:21 +000078 size_t _bs = (bufsize); /* Append size */ \
79 size_t _ns = ctx->context; /* Allocated now */ \
80 size_t _es = st->size + _bs; /* Expected size */ \
81 /* int is really a typeof(st->size): */ \
82 if((int)_es < 0) RETURN(RC_FAIL); \
83 if(_ns <= _es) { \
Lev Walkind9bd7752004-06-05 08:17:50 +000084 void *ptr; \
Lev Walkin188ed2c2004-09-13 08:31:01 +000085 /* Be nice and round to the memory allocator */ \
Lev Walkin75b1bef2005-04-25 19:38:21 +000086 do { _ns = _ns ? _ns << 1 : 16; } \
87 while(_ns <= _es); \
88 /* int is really a typeof(st->size): */ \
89 if((int)_ns < 0) RETURN(RC_FAIL); \
Lev Walkind9bd7752004-06-05 08:17:50 +000090 ptr = REALLOC(st->buf, _ns); \
91 if(ptr) { \
Lev Walkinc2346572004-08-11 09:07:36 +000092 st->buf = (uint8_t *)ptr; \
Lev Walkin75b1bef2005-04-25 19:38:21 +000093 ctx->context = _ns; \
Lev Walkind9bd7752004-06-05 08:17:50 +000094 } else { \
95 RETURN(RC_FAIL); \
96 } \
Lev Walkin7f85ef42005-07-02 20:24:27 +000097 ASN_DEBUG("Reallocating into %ld", (long)_ns); \
Lev Walkind9bd7752004-06-05 08:17:50 +000098 } \
Lev Walkin8d127872004-09-04 04:44:50 +000099 memcpy(st->buf + st->size, bufptr, _bs); \
Lev Walkind9bd7752004-06-05 08:17:50 +0000100 /* Convenient nul-termination */ \
Lev Walkin75b1bef2005-04-25 19:38:21 +0000101 st->buf[_es] = '\0'; \
102 st->size = _es; \
Lev Walkinf15320b2004-06-03 03:38:44 +0000103 } while(0)
104
105/*
Lev Walkin07f388c2004-10-11 11:43:08 +0000106 * Internal variant of the OCTET STRING.
107 */
108typedef enum OS_type {
109 _TT_GENERIC = 0, /* Just a random OCTET STRING */
110 _TT_BIT_STRING = 1, /* BIT STRING type, a special case */
Lev Walkinfdb25922005-07-21 09:32:49 +0000111 _TT_ANY = 2 /* ANY type, a special case too */
Lev Walkin07f388c2004-10-11 11:43:08 +0000112} OS_type_e;
113
114/*
Lev Walkinf15320b2004-06-03 03:38:44 +0000115 * The main reason why ASN.1 is still alive is that too much time and effort
116 * is necessary for learning it more or less adequately, thus creating a gut
117 * necessity to demonstrate that aquired skill everywhere afterwards.
118 * No, I am not going to explain what the following stuff is.
119 */
120struct _stack_el {
Lev Walkin3990ba62004-09-24 20:57:41 +0000121 ber_tlv_len_t left; /* What's left to read (or -1) */
Lev Walkin5c915992004-09-27 20:54:06 +0000122 ber_tlv_len_t got; /* What was actually processed */
Lev Walkin188ed2c2004-09-13 08:31:01 +0000123 int cont_level; /* Depth of subcontainment */
Lev Walkinf15320b2004-06-03 03:38:44 +0000124 int want_nulls; /* Want null "end of content" octets? */
125 int bits_chopped; /* Flag in BIT STRING mode */
Lev Walkin5c915992004-09-27 20:54:06 +0000126 ber_tlv_tag_t tag; /* For debugging purposes */
Lev Walkinf15320b2004-06-03 03:38:44 +0000127 struct _stack_el *prev;
128 struct _stack_el *next;
129};
130struct _stack {
131 struct _stack_el *tail;
132 struct _stack_el *cur_ptr;
133};
134
135static struct _stack_el *
Lev Walkin3990ba62004-09-24 20:57:41 +0000136OS__add_stack_el(struct _stack *st) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000137 struct _stack_el *nel;
138
Lev Walkin188ed2c2004-09-13 08:31:01 +0000139 /*
140 * Reuse the old stack frame or allocate a new one.
141 */
Lev Walkinf15320b2004-06-03 03:38:44 +0000142 if(st->cur_ptr && st->cur_ptr->next) {
143 nel = st->cur_ptr->next;
Lev Walkinf15320b2004-06-03 03:38:44 +0000144 nel->bits_chopped = 0;
Lev Walkin5c915992004-09-27 20:54:06 +0000145 nel->got = 0;
146 /* Retain the nel->cont_level, it's correct. */
Lev Walkinf15320b2004-06-03 03:38:44 +0000147 } else {
Lev Walkin814cca72004-12-15 23:23:53 +0000148 nel = (struct _stack_el *)CALLOC(1, sizeof(struct _stack_el));
Lev Walkinf15320b2004-06-03 03:38:44 +0000149 if(nel == NULL)
150 return NULL;
151
152 if(st->tail) {
Lev Walkin188ed2c2004-09-13 08:31:01 +0000153 /* Increase a subcontainment depth */
154 nel->cont_level = st->tail->cont_level + 1;
Lev Walkinf15320b2004-06-03 03:38:44 +0000155 st->tail->next = nel;
156 }
157 nel->prev = st->tail;
158 st->tail = nel;
159 }
160
161 st->cur_ptr = nel;
162
163 return nel;
164}
165
166static struct _stack *
167_new_stack() {
Lev Walkinbbd93252004-10-12 05:57:23 +0000168 return (struct _stack *)CALLOC(1, sizeof(struct _stack));
Lev Walkinf15320b2004-06-03 03:38:44 +0000169}
170
171/*
172 * Decode OCTET STRING type.
173 */
Lev Walkindc06f6b2004-10-20 15:50:55 +0000174asn_dec_rval_t
Lev Walkinde4825d2004-09-29 13:20:14 +0000175OCTET_STRING_decode_ber(asn_codec_ctx_t *opt_codec_ctx,
176 asn_TYPE_descriptor_t *td,
Lev Walkin59b176e2005-11-26 11:25:14 +0000177 void **sptr, const void *buf_ptr, size_t size, int tag_mode) {
Lev Walkinbbd93252004-10-12 05:57:23 +0000178 asn_OCTET_STRING_specifics_t *specs = td->specifics
Lev Walkindc06f6b2004-10-20 15:50:55 +0000179 ? (asn_OCTET_STRING_specifics_t *)td->specifics
180 : &asn_DEF_OCTET_STRING_specs;
Lev Walkin59b176e2005-11-26 11:25:14 +0000181 BIT_STRING_t *st = (BIT_STRING_t *)*sptr;
Lev Walkindc06f6b2004-10-20 15:50:55 +0000182 asn_dec_rval_t rval;
Lev Walkinde4825d2004-09-29 13:20:14 +0000183 asn_struct_ctx_t *ctx;
Lev Walkinf15320b2004-06-03 03:38:44 +0000184 ssize_t consumed_myself = 0;
Lev Walkinbbd93252004-10-12 05:57:23 +0000185 struct _stack *stck; /* Expectations stack structure */
Lev Walkin5c915992004-09-27 20:54:06 +0000186 struct _stack_el *sel = 0; /* Stack element */
Lev Walkinf15320b2004-06-03 03:38:44 +0000187 int tlv_constr;
Lev Walkinbbd93252004-10-12 05:57:23 +0000188 OS_type_e type_variant = (OS_type_e)specs->subvariant;
Lev Walkinf15320b2004-06-03 03:38:44 +0000189
Lev Walkincc6a9102004-09-23 22:06:26 +0000190 ASN_DEBUG("Decoding %s as %s (frame %ld)",
191 td->name,
Lev Walkinbbd93252004-10-12 05:57:23 +0000192 (type_variant == _TT_GENERIC) ?
193 "OCTET STRING" : "OS-SpecialCase",
Lev Walkincc6a9102004-09-23 22:06:26 +0000194 (long)size);
Lev Walkinf15320b2004-06-03 03:38:44 +0000195
196 /*
197 * Create the string if does not exist.
198 */
199 if(st == NULL) {
Lev Walkin59b176e2005-11-26 11:25:14 +0000200 st = (BIT_STRING_t *)(*sptr = CALLOC(1, specs->struct_size));
201 if(st == NULL) RETURN(RC_FAIL);
Lev Walkinf15320b2004-06-03 03:38:44 +0000202 }
203
204 /* Restore parsing context */
Lev Walkinbbd93252004-10-12 05:57:23 +0000205 ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset);
Lev Walkinf15320b2004-06-03 03:38:44 +0000206
207 switch(ctx->phase) {
208 case 0:
209 /*
210 * Check tags.
211 */
Lev Walkinde4825d2004-09-29 13:20:14 +0000212 rval = ber_check_tags(opt_codec_ctx, td, ctx,
Lev Walkin8e8078a2004-09-26 13:10:40 +0000213 buf_ptr, size, tag_mode, -1,
Lev Walkinf15320b2004-06-03 03:38:44 +0000214 &ctx->left, &tlv_constr);
Lev Walkin443d2512004-10-05 06:35:31 +0000215 if(rval.code != RC_OK)
216 return rval;
Lev Walkinf15320b2004-06-03 03:38:44 +0000217
Lev Walkinf15320b2004-06-03 03:38:44 +0000218 if(tlv_constr) {
219 /*
220 * Complex operation, requires stack of expectations.
221 */
222 ctx->ptr = _new_stack();
223 if(ctx->ptr) {
Lev Walkin814cca72004-12-15 23:23:53 +0000224 stck = (struct _stack *)ctx->ptr;
Lev Walkinf15320b2004-06-03 03:38:44 +0000225 } else {
226 RETURN(RC_FAIL);
227 }
228 } else {
229 /*
230 * Jump into stackless primitive decoding.
231 */
232 _CH_PHASE(ctx, 3);
Lev Walkinbbd93252004-10-12 05:57:23 +0000233 if(type_variant == _TT_ANY && tag_mode != 1)
Lev Walkin188ed2c2004-09-13 08:31:01 +0000234 APPEND(buf_ptr, rval.consumed);
Lev Walkinf15320b2004-06-03 03:38:44 +0000235 ADVANCE(rval.consumed);
236 goto phase3;
237 }
238
Lev Walkinf15320b2004-06-03 03:38:44 +0000239 NEXT_PHASE(ctx);
240 /* Fall through */
241 case 1:
242 phase1:
243 /*
244 * Fill the stack with expectations.
245 */
Lev Walkin814cca72004-12-15 23:23:53 +0000246 stck = (struct _stack *)ctx->ptr;
Lev Walkinf15320b2004-06-03 03:38:44 +0000247 sel = stck->cur_ptr;
248 do {
249 ber_tlv_tag_t tlv_tag;
250 ber_tlv_len_t tlv_len;
Lev Walkin188ed2c2004-09-13 08:31:01 +0000251 ber_tlv_tag_t expected_tag;
Lev Walkin5c915992004-09-27 20:54:06 +0000252 ssize_t tl, ll, tlvl;
Lev Walkin8e8078a2004-09-26 13:10:40 +0000253 /* This one works even if (sel->left == -1) */
254 ssize_t Left = ((!sel||(size_t)sel->left >= size)
Lev Walkin5c915992004-09-27 20:54:06 +0000255 ?(ssize_t)size:sel->left);
Lev Walkinf15320b2004-06-03 03:38:44 +0000256
Lev Walkin3990ba62004-09-24 20:57:41 +0000257
Lev Walkinabf68892004-10-26 10:12:14 +0000258 ASN_DEBUG("%p, s->l=%ld, s->wn=%ld, s->g=%ld\n", sel,
Lev Walkin1e3ccbb2004-10-26 10:56:10 +0000259 (long)(sel?sel->left:0),
260 (long)(sel?sel->want_nulls:0),
261 (long)(sel?sel->got:0)
Lev Walkin5c915992004-09-27 20:54:06 +0000262 );
263 if(sel && sel->left <= 0 && sel->want_nulls == 0) {
264 if(sel->prev) {
265 struct _stack_el *prev = sel->prev;
266 if(prev->left != -1) {
267 if(prev->left < sel->got)
268 RETURN(RC_FAIL);
269 prev->left -= sel->got;
270 }
271 prev->got += sel->got;
272 sel = stck->cur_ptr = prev;
273 if(!sel) break;
274 tlv_constr = 1;
275 continue;
276 } else {
277 sel = stck->cur_ptr = 0;
278 break; /* Nothing to wait */
279 }
280 }
281
Lev Walkin3990ba62004-09-24 20:57:41 +0000282 tl = ber_fetch_tag(buf_ptr, Left, &tlv_tag);
Lev Walkinabf68892004-10-26 10:12:14 +0000283 ASN_DEBUG("fetch tag(size=%ld,L=%ld), %sstack, left=%ld, wn=%ld, tl=%ld",
284 (long)size, (long)Left, sel?"":"!",
Lev Walkin1e3ccbb2004-10-26 10:56:10 +0000285 (long)(sel?sel->left:0),
286 (long)(sel?sel->want_nulls:0),
Lev Walkinabf68892004-10-26 10:12:14 +0000287 (long)tl);
Lev Walkinf15320b2004-06-03 03:38:44 +0000288 switch(tl) {
289 case -1: RETURN(RC_FAIL);
290 case 0: RETURN(RC_WMORE);
291 }
292
293 tlv_constr = BER_TLV_CONSTRUCTED(buf_ptr);
294
295 ll = ber_fetch_length(tlv_constr,
Lev Walkin8c3b8542005-03-10 18:52:02 +0000296 (const char *)buf_ptr + tl,Left - tl,&tlv_len);
Lev Walkina6a926a2005-03-02 01:54:28 +0000297 ASN_DEBUG("Got tag=%s, tc=%d, left=%ld, tl=%ld, len=%ld, ll=%ld",
Lev Walkin8d127872004-09-04 04:44:50 +0000298 ber_tlv_tag_string(tlv_tag), tlv_constr,
Lev Walkina6a926a2005-03-02 01:54:28 +0000299 (long)Left, (long)tl, (long)tlv_len, (long)ll);
Lev Walkinf15320b2004-06-03 03:38:44 +0000300 switch(ll) {
301 case -1: RETURN(RC_FAIL);
302 case 0: RETURN(RC_WMORE);
303 }
304
Lev Walkin8d127872004-09-04 04:44:50 +0000305 if(sel && sel->want_nulls
Lev Walkin8c3b8542005-03-10 18:52:02 +0000306 && ((const uint8_t *)buf_ptr)[0] == 0
307 && ((const uint8_t *)buf_ptr)[1] == 0)
Lev Walkinf15320b2004-06-03 03:38:44 +0000308 {
Lev Walkin8d127872004-09-04 04:44:50 +0000309
310 ASN_DEBUG("Eat EOC; wn=%d--", sel->want_nulls);
311
Lev Walkinbbd93252004-10-12 05:57:23 +0000312 if(type_variant == _TT_ANY
Lev Walkin07f388c2004-10-11 11:43:08 +0000313 && (tag_mode != 1 || sel->cont_level))
314 APPEND("\0\0", 2);
Lev Walkin5c915992004-09-27 20:54:06 +0000315
316 ADVANCE(2);
317 sel->got += 2;
318 if(sel->left != -1) {
319 sel->left -= 2; /* assert(sel->left >= 2) */
320 }
321
Lev Walkinf15320b2004-06-03 03:38:44 +0000322 sel->want_nulls--;
323 if(sel->want_nulls == 0) {
324 /* Move to the next expectation */
Lev Walkin5c915992004-09-27 20:54:06 +0000325 sel->left = 0;
Lev Walkinf15320b2004-06-03 03:38:44 +0000326 tlv_constr = 1;
Lev Walkinf15320b2004-06-03 03:38:44 +0000327 }
Lev Walkin8d127872004-09-04 04:44:50 +0000328
329 continue;
Lev Walkin188ed2c2004-09-13 08:31:01 +0000330 }
331
332 /*
333 * Set up expected tags,
334 * depending on ASN.1 type being decoded.
335 */
Lev Walkinbbd93252004-10-12 05:57:23 +0000336 switch(type_variant) {
Lev Walkin188ed2c2004-09-13 08:31:01 +0000337 case _TT_BIT_STRING:
338 /* X.690: 8.6.4.1, NOTE 2 */
339 /* Fall through */
340 case _TT_GENERIC:
341 default:
342 if(sel) {
343 int level = sel->cont_level;
344 if(level < td->all_tags_count) {
345 expected_tag = td->all_tags[level];
346 break;
347 } else if(td->all_tags_count) {
348 expected_tag = td->all_tags
349 [td->all_tags_count - 1];
350 break;
351 }
352 /* else, Fall through */
353 }
354 /* Fall through */
355 case _TT_ANY:
356 expected_tag = tlv_tag;
357 break;
358 }
359
360
361 if(tlv_tag != expected_tag) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000362 char buf[2][32];
363 ber_tlv_tag_snprint(tlv_tag,
364 buf[0], sizeof(buf[0]));
365 ber_tlv_tag_snprint(td->tags[td->tags_count-1],
366 buf[1], sizeof(buf[1]));
367 ASN_DEBUG("Tag does not match expectation: %s != %s",
368 buf[0], buf[1]);
369 RETURN(RC_FAIL);
370 }
371
Lev Walkinde4825d2004-09-29 13:20:14 +0000372 tlvl = tl + ll; /* Combined length of T and L encoding */
373 if((tlv_len + tlvl) < 0) {
374 /* tlv_len value is too big */
375 ASN_DEBUG("TLV encoding + length (%ld) is too big",
376 (long)tlv_len);
377 RETURN(RC_FAIL);
378 }
379
Lev Walkinf15320b2004-06-03 03:38:44 +0000380 /*
381 * Append a new expectation.
382 */
Lev Walkin3990ba62004-09-24 20:57:41 +0000383 sel = OS__add_stack_el(stck);
Lev Walkin5c915992004-09-27 20:54:06 +0000384 if(!sel) RETURN(RC_FAIL);
Lev Walkinf15320b2004-06-03 03:38:44 +0000385
Lev Walkin5c915992004-09-27 20:54:06 +0000386 sel->tag = tlv_tag;
387
388 sel->want_nulls = (tlv_len==-1);
389 if(sel->prev && sel->prev->left != -1) {
390 /* Check that the parent frame is big enough */
391 if(sel->prev->left < tlvl + (tlv_len==-1?0:tlv_len))
392 RETURN(RC_FAIL);
393 if(tlv_len == -1)
394 sel->left = sel->prev->left - tlvl;
395 else
396 sel->left = tlv_len;
397 } else {
398 sel->left = tlv_len;
399 }
Lev Walkinbbd93252004-10-12 05:57:23 +0000400 if(type_variant == _TT_ANY
Lev Walkin07f388c2004-10-11 11:43:08 +0000401 && (tag_mode != 1 || sel->cont_level))
402 APPEND(buf_ptr, tlvl);
Lev Walkin5c915992004-09-27 20:54:06 +0000403 sel->got += tlvl;
404 ADVANCE(tlvl);
405
Lev Walkinabf68892004-10-26 10:12:14 +0000406 ASN_DEBUG("+EXPECT2 got=%ld left=%ld, wn=%d, clvl=%d",
407 (long)sel->got, (long)sel->left,
408 sel->want_nulls, sel->cont_level);
Lev Walkin5c915992004-09-27 20:54:06 +0000409
Lev Walkinf15320b2004-06-03 03:38:44 +0000410 } while(tlv_constr);
411 if(sel == NULL) {
412 /* Finished operation, "phase out" */
Lev Walkin188ed2c2004-09-13 08:31:01 +0000413 ASN_DEBUG("Phase out");
Lev Walkinf15320b2004-06-03 03:38:44 +0000414 _CH_PHASE(ctx, +3);
415 break;
416 }
417
418 NEXT_PHASE(ctx);
419 /* Fall through */
420 case 2:
Lev Walkin814cca72004-12-15 23:23:53 +0000421 stck = (struct _stack *)ctx->ptr;
Lev Walkinf15320b2004-06-03 03:38:44 +0000422 sel = stck->cur_ptr;
Lev Walkin5c915992004-09-27 20:54:06 +0000423 ASN_DEBUG("Phase 2: Need %ld bytes, size=%ld, alrg=%ld, wn=%d",
424 (long)sel->left, (long)size, (long)sel->got,
425 sel->want_nulls);
Lev Walkinf15320b2004-06-03 03:38:44 +0000426 {
427 ber_tlv_len_t len;
428
429 assert(sel->left >= 0);
430
Lev Walkinec1ffd42004-08-18 04:53:32 +0000431 len = ((ber_tlv_len_t)size < sel->left)
432 ? (ber_tlv_len_t)size : sel->left;
Lev Walkinf15320b2004-06-03 03:38:44 +0000433 if(len > 0) {
Lev Walkinbbd93252004-10-12 05:57:23 +0000434 if(type_variant == _TT_BIT_STRING
Lev Walkin188ed2c2004-09-13 08:31:01 +0000435 && sel->bits_chopped == 0) {
Lev Walkinbbd93252004-10-12 05:57:23 +0000436 /* Put the unused-bits-octet away */
Lev Walkin8c3b8542005-03-10 18:52:02 +0000437 st->bits_unused = *(const uint8_t *)buf_ptr;
438 APPEND(((const char *)buf_ptr+1), (len - 1));
Lev Walkinf15320b2004-06-03 03:38:44 +0000439 sel->bits_chopped = 1;
440 } else {
441 APPEND(buf_ptr, len);
442 }
443 ADVANCE(len);
444 sel->left -= len;
Lev Walkin5c915992004-09-27 20:54:06 +0000445 sel->got += len;
Lev Walkinf15320b2004-06-03 03:38:44 +0000446 }
447
Lev Walkin5c915992004-09-27 20:54:06 +0000448 if(sel->left) {
449 ASN_DEBUG("OS left %ld, size = %ld, wn=%d\n",
450 (long)sel->left, (long)size, sel->want_nulls);
Lev Walkinf15320b2004-06-03 03:38:44 +0000451 RETURN(RC_WMORE);
Lev Walkinf15320b2004-06-03 03:38:44 +0000452 }
Lev Walkin5c915992004-09-27 20:54:06 +0000453
454 PREV_PHASE(ctx);
455 goto phase1;
Lev Walkinf15320b2004-06-03 03:38:44 +0000456 }
457 break;
458 case 3:
459 phase3:
460 /*
461 * Primitive form, no stack required.
462 */
Lev Walkinbbd93252004-10-12 05:57:23 +0000463 assert(ctx->left >= 0);
464
Lev Walkind9bd7752004-06-05 08:17:50 +0000465 if(size < (size_t)ctx->left) {
Lev Walkinbbd93252004-10-12 05:57:23 +0000466 if(!size) RETURN(RC_WMORE);
Lev Walkin75b1bef2005-04-25 19:38:21 +0000467 if(type_variant == _TT_BIT_STRING && !ctx->context) {
Lev Walkin8c3b8542005-03-10 18:52:02 +0000468 st->bits_unused = *(const uint8_t *)buf_ptr;
Lev Walkinbbd93252004-10-12 05:57:23 +0000469 ctx->left--;
470 ADVANCE(1);
471 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000472 APPEND(buf_ptr, size);
Lev Walkin75b1bef2005-04-25 19:38:21 +0000473 assert(ctx->context > 0);
Lev Walkinf15320b2004-06-03 03:38:44 +0000474 ctx->left -= size;
475 ADVANCE(size);
476 RETURN(RC_WMORE);
477 } else {
Lev Walkinbbd93252004-10-12 05:57:23 +0000478 if(type_variant == _TT_BIT_STRING
Lev Walkin75b1bef2005-04-25 19:38:21 +0000479 && !ctx->context && ctx->left) {
Lev Walkin8c3b8542005-03-10 18:52:02 +0000480 st->bits_unused = *(const uint8_t *)buf_ptr;
Lev Walkinbbd93252004-10-12 05:57:23 +0000481 ctx->left--;
482 ADVANCE(1);
483 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000484 APPEND(buf_ptr, ctx->left);
485 ADVANCE(ctx->left);
486 ctx->left = 0;
487
488 NEXT_PHASE(ctx);
489 }
490 break;
491 }
492
Lev Walkin5c915992004-09-27 20:54:06 +0000493 if(sel) {
494 ASN_DEBUG("3sel p=%p, wn=%d, l=%ld, g=%ld, size=%ld",
495 sel->prev, sel->want_nulls,
496 (long)sel->left, (long)sel->got, (long)size);
497 if(sel->prev || sel->want_nulls > 1 || sel->left > 0) {
498 RETURN(RC_WMORE);
499 }
500 }
501
Lev Walkinf15320b2004-06-03 03:38:44 +0000502 /*
503 * BIT STRING-specific processing.
504 */
Lev Walkinbbd93252004-10-12 05:57:23 +0000505 if(type_variant == _TT_BIT_STRING && st->size) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000506 /* Finalize BIT STRING: zero out unused bits. */
Lev Walkinbbd93252004-10-12 05:57:23 +0000507 st->buf[st->size-1] &= 0xff << st->bits_unused;
Lev Walkinf15320b2004-06-03 03:38:44 +0000508 }
509
Lev Walkinabf68892004-10-26 10:12:14 +0000510 ASN_DEBUG("Took %ld bytes to encode %s: [%s]:%ld",
511 (long)consumed_myself, td->name,
Lev Walkinbbd93252004-10-12 05:57:23 +0000512 (type_variant == _TT_GENERIC) ? (char *)st->buf : "<data>",
Lev Walkinabf68892004-10-26 10:12:14 +0000513 (long)st->size);
Lev Walkinf15320b2004-06-03 03:38:44 +0000514
Lev Walkinf15320b2004-06-03 03:38:44 +0000515
Lev Walkin5c915992004-09-27 20:54:06 +0000516 RETURN(RC_OK);
Lev Walkinf15320b2004-06-03 03:38:44 +0000517}
518
519/*
520 * Encode OCTET STRING type using DER.
521 */
Lev Walkina9cc46e2004-09-22 16:06:28 +0000522asn_enc_rval_t
Lev Walkinbbd93252004-10-12 05:57:23 +0000523OCTET_STRING_encode_der(asn_TYPE_descriptor_t *td, void *sptr,
Lev Walkinf15320b2004-06-03 03:38:44 +0000524 int tag_mode, ber_tlv_tag_t tag,
525 asn_app_consume_bytes_f *cb, void *app_key) {
Lev Walkinbbd93252004-10-12 05:57:23 +0000526 asn_enc_rval_t er;
527 asn_OCTET_STRING_specifics_t *specs = td->specifics
Lev Walkindc06f6b2004-10-20 15:50:55 +0000528 ? (asn_OCTET_STRING_specifics_t *)td->specifics
529 : &asn_DEF_OCTET_STRING_specs;
Lev Walkinbbd93252004-10-12 05:57:23 +0000530 BIT_STRING_t *st = (BIT_STRING_t *)sptr;
531 OS_type_e type_variant = (OS_type_e)specs->subvariant;
532 int fix_last_byte = 0;
Lev Walkinf15320b2004-06-03 03:38:44 +0000533
534 ASN_DEBUG("%s %s as OCTET STRING",
Lev Walkin1f670c12004-09-02 12:57:25 +0000535 cb?"Estimating":"Encoding", td->name);
Lev Walkinf15320b2004-06-03 03:38:44 +0000536
537 /*
Lev Walkinbbd93252004-10-12 05:57:23 +0000538 * Write tags.
Lev Walkinf15320b2004-06-03 03:38:44 +0000539 */
Lev Walkinbbd93252004-10-12 05:57:23 +0000540 if(type_variant != _TT_ANY || tag_mode == 1) {
541 er.encoded = der_write_tags(td,
542 (type_variant == _TT_BIT_STRING) + st->size,
543 tag_mode, type_variant == _TT_ANY, tag, cb, app_key);
544 if(er.encoded == -1) {
545 er.failed_type = td;
546 er.structure_ptr = sptr;
547 return er;
Lev Walkinf15320b2004-06-03 03:38:44 +0000548 }
Lev Walkinbbd93252004-10-12 05:57:23 +0000549 } else {
550 /* Disallow: [<tag>] IMPLICIT ANY */
551 assert(type_variant != _TT_ANY || tag_mode != -1);
552 er.encoded = 0;
553 }
554
555 if(!cb) {
556 er.encoded += (type_variant == _TT_BIT_STRING) + st->size;
Lev Walkin59b176e2005-11-26 11:25:14 +0000557 _ASN_ENCODED_OK(er);
Lev Walkinf15320b2004-06-03 03:38:44 +0000558 }
559
Lev Walkin07f388c2004-10-11 11:43:08 +0000560 /*
Lev Walkinbbd93252004-10-12 05:57:23 +0000561 * Prepare to deal with the last octet of BIT STRING.
Lev Walkin07f388c2004-10-11 11:43:08 +0000562 */
Lev Walkinbbd93252004-10-12 05:57:23 +0000563 if(type_variant == _TT_BIT_STRING) {
564 uint8_t b = st->bits_unused & 0x07;
565 if(b && st->size) fix_last_byte = 1;
566 _ASN_CALLBACK(&b, 1);
567 er.encoded++;
Lev Walkinf15320b2004-06-03 03:38:44 +0000568 }
569
Lev Walkinbbd93252004-10-12 05:57:23 +0000570 /* Invoke callback for the main part of the buffer */
571 _ASN_CALLBACK(st->buf, st->size - fix_last_byte);
Lev Walkinf15320b2004-06-03 03:38:44 +0000572
Lev Walkinbbd93252004-10-12 05:57:23 +0000573 /* The last octet should be stripped off the unused bits */
574 if(fix_last_byte) {
575 uint8_t b = st->buf[st->size-1] & (0xff << st->bits_unused);
576 _ASN_CALLBACK(&b, 1);
Lev Walkinf15320b2004-06-03 03:38:44 +0000577 }
578
Lev Walkinbbd93252004-10-12 05:57:23 +0000579 er.encoded += st->size;
Lev Walkin59b176e2005-11-26 11:25:14 +0000580 _ASN_ENCODED_OK(er);
Lev Walkinbbd93252004-10-12 05:57:23 +0000581cb_failed:
582 _ASN_ENCODE_FAILED;
Lev Walkinf15320b2004-06-03 03:38:44 +0000583}
584
Lev Walkina9cc46e2004-09-22 16:06:28 +0000585asn_enc_rval_t
Lev Walkinde4825d2004-09-29 13:20:14 +0000586OCTET_STRING_encode_xer(asn_TYPE_descriptor_t *td, void *sptr,
Lev Walkina9cc46e2004-09-22 16:06:28 +0000587 int ilevel, enum xer_encoder_flags_e flags,
588 asn_app_consume_bytes_f *cb, void *app_key) {
589 static const char *h2c = "0123456789ABCDEF";
590 const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr;
591 asn_enc_rval_t er;
592 char scratch[16 * 3 + 4];
593 char *p = scratch;
594 uint8_t *buf;
595 uint8_t *end;
596 size_t i;
597
Lev Walkin942fd082004-10-03 09:13:02 +0000598 if(!st || !st->buf)
599 _ASN_ENCODE_FAILED;
Lev Walkina9cc46e2004-09-22 16:06:28 +0000600
601 er.encoded = 0;
602
603 /*
604 * Dump the contents of the buffer in hexadecimal.
605 */
606 buf = st->buf;
607 end = buf + st->size;
608 if(flags & XER_F_CANONICAL) {
609 char *scend = scratch + (sizeof(scratch) - 2);
610 for(; buf < end; buf++) {
611 if(p >= scend) {
612 _ASN_CALLBACK(scratch, p - scratch);
613 er.encoded += p - scratch;
614 p = scratch;
615 }
616 *p++ = h2c[(*buf >> 4) & 0x0F];
617 *p++ = h2c[*buf & 0x0F];
618 }
Lev Walkincc6a9102004-09-23 22:06:26 +0000619
620 _ASN_CALLBACK(scratch, p-scratch); /* Dump the rest */
621 er.encoded += p - scratch;
Lev Walkina9cc46e2004-09-22 16:06:28 +0000622 } else {
623 for(i = 0; buf < end; buf++, i++) {
624 if(!(i % 16) && (i || st->size > 16)) {
625 _ASN_CALLBACK(scratch, p-scratch);
626 er.encoded += (p-scratch);
627 p = scratch;
628 _i_ASN_TEXT_INDENT(1, ilevel);
629 }
630 *p++ = h2c[(*buf >> 4) & 0x0F];
631 *p++ = h2c[*buf & 0x0F];
632 *p++ = 0x20;
633 }
Lev Walkincc6a9102004-09-23 22:06:26 +0000634 if(p - scratch) {
635 p--; /* Remove the tail space */
636 _ASN_CALLBACK(scratch, p-scratch); /* Dump the rest */
637 er.encoded += p - scratch;
638 if(st->size > 16)
639 _i_ASN_TEXT_INDENT(1, ilevel-1);
640 }
Lev Walkina9cc46e2004-09-22 16:06:28 +0000641 }
642
Lev Walkin59b176e2005-11-26 11:25:14 +0000643 _ASN_ENCODED_OK(er);
Lev Walkin942fd082004-10-03 09:13:02 +0000644cb_failed:
645 _ASN_ENCODE_FAILED;
Lev Walkina9cc46e2004-09-22 16:06:28 +0000646}
647
Lev Walkin9ca81892004-10-03 10:54:25 +0000648static struct OCTET_STRING__xer_escape_table_s {
649 char *string;
650 int size;
651} OCTET_STRING__xer_escape_table[] = {
652#define OSXET(s) { s, sizeof(s) - 1 }
653 OSXET("\074\156\165\154\057\076"), /* <nul/> */
654 OSXET("\074\163\157\150\057\076"), /* <soh/> */
655 OSXET("\074\163\164\170\057\076"), /* <stx/> */
656 OSXET("\074\145\164\170\057\076"), /* <etx/> */
657 OSXET("\074\145\157\164\057\076"), /* <eot/> */
658 OSXET("\074\145\156\161\057\076"), /* <enq/> */
659 OSXET("\074\141\143\153\057\076"), /* <ack/> */
660 OSXET("\074\142\145\154\057\076"), /* <bel/> */
661 OSXET("\074\142\163\057\076"), /* <bs/> */
662 OSXET("\011"), /* \t */
663 OSXET("\012"), /* \n */
664 OSXET("\074\166\164\057\076"), /* <vt/> */
665 OSXET("\074\146\146\057\076"), /* <ff/> */
666 OSXET("\015"), /* \r */
667 OSXET("\074\163\157\057\076"), /* <so/> */
668 OSXET("\074\163\151\057\076"), /* <si/> */
669 OSXET("\074\144\154\145\057\076"), /* <dle/> */
670 OSXET("\074\144\143\061\057\076"), /* <de1/> */
671 OSXET("\074\144\143\062\057\076"), /* <de2/> */
672 OSXET("\074\144\143\063\057\076"), /* <de3/> */
673 OSXET("\074\144\143\064\057\076"), /* <de4/> */
674 OSXET("\074\156\141\153\057\076"), /* <nak/> */
675 OSXET("\074\163\171\156\057\076"), /* <syn/> */
676 OSXET("\074\145\164\142\057\076"), /* <etb/> */
677 OSXET("\074\143\141\156\057\076"), /* <can/> */
678 OSXET("\074\145\155\057\076"), /* <em/> */
679 OSXET("\074\163\165\142\057\076"), /* <sub/> */
680 OSXET("\074\145\163\143\057\076"), /* <esc/> */
681 OSXET("\074\151\163\064\057\076"), /* <is4/> */
682 OSXET("\074\151\163\063\057\076"), /* <is3/> */
683 OSXET("\074\151\163\062\057\076"), /* <is2/> */
684 OSXET("\074\151\163\061\057\076"), /* <is1/> */
685 { 0, 0 }, /* " " */
686 { 0, 0 }, /* ! */
687 { 0, 0 }, /* \" */
688 { 0, 0 }, /* # */
689 { 0, 0 }, /* $ */
690 { 0, 0 }, /* % */
691 OSXET("\046\141\155\160\073"), /* &amp; */
692 { 0, 0 }, /* ' */
693 {0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, /* ()*+,-./ */
694 {0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, /* 01234567 */
695 {0,0},{0,0},{0,0},{0,0}, /* 89:; */
696 OSXET("\046\154\164\073"), /* &lt; */
697 { 0, 0 }, /* = */
698 OSXET("\046\147\164\073"), /* &gt; */
699};
700
Lev Walkindc06f6b2004-10-20 15:50:55 +0000701static int
Lev Walkin0fab1a62005-03-09 22:19:25 +0000702OS__check_escaped_control_char(const void *buf, int size) {
Lev Walkindc06f6b2004-10-20 15:50:55 +0000703 size_t i;
704 /*
705 * Inefficient algorithm which translates the escape sequences
706 * defined above into characters. Returns -1 if not found.
707 * TODO: replace by a faster algorithm (bsearch(), hash or
708 * nested table lookups).
709 */
710 for(i = 0; i < 32 /* Don't spend time on the bottom half */; i++) {
711 struct OCTET_STRING__xer_escape_table_s *el;
712 el = &OCTET_STRING__xer_escape_table[i];
713 if(el->size == size && memcmp(buf, el->string, size) == 0)
714 return i;
715 }
716 return -1;
717}
718
719static int
Lev Walkin0fab1a62005-03-09 22:19:25 +0000720OCTET_STRING__handle_control_chars(void *struct_ptr, const void *chunk_buf, size_t chunk_size) {
Lev Walkindc06f6b2004-10-20 15:50:55 +0000721 /*
722 * This might be one of the escape sequences
723 * for control characters. Check it out.
724 * #11.15.5
725 */
726 int control_char = OS__check_escaped_control_char(chunk_buf,chunk_size);
727 if(control_char >= 0) {
728 OCTET_STRING_t *st = (OCTET_STRING_t *)struct_ptr;
729 void *p = REALLOC(st->buf, st->size + 2);
730 if(p) {
731 st->buf = (uint8_t *)p;
732 st->buf[st->size++] = control_char;
733 st->buf[st->size] = '\0'; /* nul-termination */
734 return 0;
735 }
736 }
737
738 return -1; /* No, it's not */
739}
740
Lev Walkina9cc46e2004-09-22 16:06:28 +0000741asn_enc_rval_t
Lev Walkindc06f6b2004-10-20 15:50:55 +0000742OCTET_STRING_encode_xer_utf8(asn_TYPE_descriptor_t *td, void *sptr,
Lev Walkina9cc46e2004-09-22 16:06:28 +0000743 int ilevel, enum xer_encoder_flags_e flags,
744 asn_app_consume_bytes_f *cb, void *app_key) {
745 const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr;
746 asn_enc_rval_t er;
Lev Walkin9ca81892004-10-03 10:54:25 +0000747 uint8_t *buf, *end;
748 uint8_t *ss; /* Sequence start */
749 ssize_t encoded_len = 0;
Lev Walkina9cc46e2004-09-22 16:06:28 +0000750
751 (void)ilevel; /* Unused argument */
752 (void)flags; /* Unused argument */
753
754 if(!st || !st->buf)
755 _ASN_ENCODE_FAILED;
756
Lev Walkin9ca81892004-10-03 10:54:25 +0000757 buf = st->buf;
758 end = buf + st->size;
759 for(ss = buf; buf < end; buf++) {
Lev Walkin443d2512004-10-05 06:35:31 +0000760 unsigned int ch = *buf;
Lev Walkin9ca81892004-10-03 10:54:25 +0000761 int s_len; /* Special encoding sequence length */
Lev Walkina9cc46e2004-09-22 16:06:28 +0000762
Lev Walkin9ca81892004-10-03 10:54:25 +0000763 /*
764 * Escape certain characters: X.680/11.15
765 */
766 if(ch < sizeof(OCTET_STRING__xer_escape_table)
767 /sizeof(OCTET_STRING__xer_escape_table[0])
768 && (s_len = OCTET_STRING__xer_escape_table[ch].size)) {
769 if(((buf - ss) && cb(ss, buf - ss, app_key) < 0)
770 || cb(OCTET_STRING__xer_escape_table[ch].string, s_len,
771 app_key) < 0)
772 _ASN_ENCODE_FAILED;
773 encoded_len += (buf - ss) + s_len;
774 ss = buf + 1;
775 }
776 }
777
778 encoded_len += (buf - ss);
779 if((buf - ss) && cb(ss, buf - ss, app_key) < 0)
780 _ASN_ENCODE_FAILED;
781
782 er.encoded = encoded_len;
Lev Walkin59b176e2005-11-26 11:25:14 +0000783 _ASN_ENCODED_OK(er);
Lev Walkina9cc46e2004-09-22 16:06:28 +0000784}
785
Lev Walkindc06f6b2004-10-20 15:50:55 +0000786/*
787 * Convert from hexadecimal format (cstring): "AB CD EF"
788 */
Lev Walkin0fab1a62005-03-09 22:19:25 +0000789static ssize_t OCTET_STRING__convert_hexadecimal(void *sptr, const void *chunk_buf, size_t chunk_size, int have_more) {
Lev Walkindc06f6b2004-10-20 15:50:55 +0000790 OCTET_STRING_t *st = (OCTET_STRING_t *)sptr;
Lev Walkin0fab1a62005-03-09 22:19:25 +0000791 const char *chunk_stop = (const char *)chunk_buf;
792 const char *p = chunk_stop;
793 const char *pend = p + chunk_size;
Lev Walkindc06f6b2004-10-20 15:50:55 +0000794 unsigned int clv = 0;
795 int half = 0; /* Half bit */
796 uint8_t *buf;
797
798 /* Reallocate buffer according to high cap estimation */
799 ssize_t _ns = st->size + (chunk_size + 1) / 2;
800 void *nptr = REALLOC(st->buf, _ns + 1);
801 if(!nptr) return -1;
802 st->buf = (uint8_t *)nptr;
803 buf = st->buf + st->size;
804
805 /*
806 * If something like " a b c " appears here, the " a b":3 will be
807 * converted, and the rest skipped. That is, unless buf_size is greater
808 * than chunk_size, then it'll be equivalent to "ABC0".
809 */
810 for(; p < pend; p++) {
Lev Walkin0fab1a62005-03-09 22:19:25 +0000811 int ch = *(const unsigned char *)p;
Lev Walkindc06f6b2004-10-20 15:50:55 +0000812 switch(ch) {
813 case 0x09: case 0x0a: case 0x0c: case 0x0d:
814 case 0x20:
815 /* Ignore whitespace */
816 continue;
817 case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: /*01234*/
818 case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: /*56789*/
819 clv = (clv << 4) + (ch - 0x30);
820 break;
821 case 0x41: case 0x42: case 0x43: /* ABC */
822 case 0x44: case 0x45: case 0x46: /* DEF */
Lev Walkin3ae21bd2005-02-21 14:43:48 +0000823 clv = (clv << 4) + (ch - 0x41 + 10);
Lev Walkindc06f6b2004-10-20 15:50:55 +0000824 break;
825 case 0x61: case 0x62: case 0x63: /* abc */
826 case 0x64: case 0x65: case 0x66: /* def */
Lev Walkin3ae21bd2005-02-21 14:43:48 +0000827 clv = (clv << 4) + (ch - 0x61 + 10);
Lev Walkindc06f6b2004-10-20 15:50:55 +0000828 break;
829 default:
830 *buf = 0; /* JIC */
831 return -1;
832 }
833 if(half++) {
834 half = 0;
835 *buf++ = clv;
836 chunk_stop = p + 1;
837 }
838 }
839
840 /*
841 * Check partial decoding.
842 */
843 if(half) {
844 if(have_more) {
845 /*
846 * Partial specification is fine,
847 * because no more more PXER_TEXT data is available.
848 */
849 *buf++ = clv << 4;
850 chunk_stop = p;
851 }
852 } else {
853 chunk_stop = p;
854 }
855
856 st->size = buf - st->buf; /* Adjust the buffer size */
857 assert(st->size <= _ns);
858 st->buf[st->size] = 0; /* Courtesy termination */
859
Lev Walkin0fab1a62005-03-09 22:19:25 +0000860 return (chunk_stop - (const char *)chunk_buf); /* Converted size */
Lev Walkindc06f6b2004-10-20 15:50:55 +0000861}
862
863/*
864 * Convert from binary format: "00101011101"
865 */
Lev Walkin0fab1a62005-03-09 22:19:25 +0000866static ssize_t OCTET_STRING__convert_binary(void *sptr, const void *chunk_buf, size_t chunk_size, int have_more) {
Lev Walkindc06f6b2004-10-20 15:50:55 +0000867 BIT_STRING_t *st = (BIT_STRING_t *)sptr;
Lev Walkin0fab1a62005-03-09 22:19:25 +0000868 const char *p = (const char *)chunk_buf;
869 const char *pend = p + chunk_size;
Lev Walkindc06f6b2004-10-20 15:50:55 +0000870 int bits_unused = st->bits_unused & 0x7;
871 uint8_t *buf;
872
873 /* Reallocate buffer according to high cap estimation */
874 ssize_t _ns = st->size + (chunk_size + 7) / 8;
875 void *nptr = REALLOC(st->buf, _ns + 1);
876 if(!nptr) return -1;
877 st->buf = (uint8_t *)nptr;
878 buf = st->buf + st->size;
879
880 (void)have_more;
881
882 if(bits_unused == 0)
883 bits_unused = 8;
884 else if(st->size)
885 buf--;
886
887 /*
888 * Convert series of 0 and 1 into the octet string.
889 */
890 for(; p < pend; p++) {
Lev Walkin0fab1a62005-03-09 22:19:25 +0000891 int ch = *(const unsigned char *)p;
Lev Walkindc06f6b2004-10-20 15:50:55 +0000892 switch(ch) {
893 case 0x09: case 0x0a: case 0x0c: case 0x0d:
894 case 0x20:
895 /* Ignore whitespace */
896 break;
897 case 0x30:
898 case 0x31:
899 if(bits_unused-- <= 0) {
900 *++buf = 0; /* Clean the cell */
901 bits_unused = 7;
902 }
903 *buf |= (ch&1) << bits_unused;
904 break;
905 default:
906 st->bits_unused = bits_unused;
907 return -1;
908 }
909 }
910
911 if(bits_unused == 8) {
912 st->size = buf - st->buf;
913 st->bits_unused = 0;
914 } else {
915 st->size = buf - st->buf + 1;
916 st->bits_unused = bits_unused;
917 }
918
919 assert(st->size <= _ns);
920 st->buf[st->size] = 0; /* Courtesy termination */
921
922 return chunk_size; /* Converted in full */
923}
924
925/*
926 * Something like strtod(), but with stricter rules.
927 */
928static int
Lev Walkin0fab1a62005-03-09 22:19:25 +0000929OS__strtoent(int base, const char *buf, const char *end, int32_t *ret_value) {
Lev Walkin33700162004-10-26 09:03:31 +0000930 int32_t val = 0;
Lev Walkin0fab1a62005-03-09 22:19:25 +0000931 const char *p;
Lev Walkindc06f6b2004-10-20 15:50:55 +0000932
933 for(p = buf; p < end; p++) {
934 int ch = *p;
Lev Walkinb0f3db62005-07-03 05:30:15 +0000935
936 /* Strange huge value */
937 if((val * base + base) < 0)
938 return -1;
939
Lev Walkindc06f6b2004-10-20 15:50:55 +0000940 switch(ch) {
941 case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: /*01234*/
942 case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: /*56789*/
943 val = val * base + (ch - 0x30);
944 break;
945 case 0x41: case 0x42: case 0x43: /* ABC */
946 case 0x44: case 0x45: case 0x46: /* DEF */
Lev Walkin3ae21bd2005-02-21 14:43:48 +0000947 val = val * base + (ch - 0x41 + 10);
Lev Walkindc06f6b2004-10-20 15:50:55 +0000948 break;
949 case 0x61: case 0x62: case 0x63: /* abc */
950 case 0x64: case 0x65: case 0x66: /* def */
Lev Walkin3ae21bd2005-02-21 14:43:48 +0000951 val = val * base + (ch - 0x61 + 10);
Lev Walkindc06f6b2004-10-20 15:50:55 +0000952 break;
953 case 0x3b: /* ';' */
Lev Walkin0fab1a62005-03-09 22:19:25 +0000954 *ret_value = val;
Lev Walkindc06f6b2004-10-20 15:50:55 +0000955 return (p - buf) + 1;
956 default:
957 return -1; /* Character set error */
958 }
959 }
960
Lev Walkinb0f3db62005-07-03 05:30:15 +0000961 *ret_value = -1;
Lev Walkindc06f6b2004-10-20 15:50:55 +0000962 return (p - buf);
963}
964
965/*
966 * Convert from the plain UTF-8 format, expanding entity references: "2 &lt; 3"
967 */
Lev Walkin0fab1a62005-03-09 22:19:25 +0000968static ssize_t OCTET_STRING__convert_entrefs(void *sptr, const void *chunk_buf, size_t chunk_size, int have_more) {
Lev Walkindc06f6b2004-10-20 15:50:55 +0000969 OCTET_STRING_t *st = (OCTET_STRING_t *)sptr;
Lev Walkin0fab1a62005-03-09 22:19:25 +0000970 const char *p = (const char *)chunk_buf;
971 const char *pend = p + chunk_size;
Lev Walkindc06f6b2004-10-20 15:50:55 +0000972 uint8_t *buf;
973
974 /* Reallocate buffer */
975 ssize_t _ns = st->size + chunk_size;
976 void *nptr = REALLOC(st->buf, _ns + 1);
977 if(!nptr) return -1;
978 st->buf = (uint8_t *)nptr;
979 buf = st->buf + st->size;
980
981 /*
982 * Convert series of 0 and 1 into the octet string.
983 */
984 for(; p < pend; p++) {
Lev Walkin0fab1a62005-03-09 22:19:25 +0000985 int ch = *(const unsigned char *)p;
Lev Walkindc06f6b2004-10-20 15:50:55 +0000986 int len; /* Length of the rest of the chunk */
987
988 if(ch != 0x26 /* '&' */) {
989 *buf++ = ch;
990 continue; /* That was easy... */
991 }
992
993 /*
994 * Process entity reference.
995 */
Lev Walkin0fab1a62005-03-09 22:19:25 +0000996 len = chunk_size - (p - (const char *)chunk_buf);
Lev Walkindc06f6b2004-10-20 15:50:55 +0000997 if(len == 1 /* "&" */) goto want_more;
998 if(p[1] == 0x23 /* '#' */) {
Lev Walkin0fab1a62005-03-09 22:19:25 +0000999 const char *pval; /* Pointer to start of digits */
Lev Walkinbc0dce32006-07-27 09:56:13 +00001000 int32_t val = 0; /* Entity reference value */
Lev Walkindc06f6b2004-10-20 15:50:55 +00001001 int base;
1002
1003 if(len == 2 /* "&#" */) goto want_more;
1004 if(p[2] == 0x78 /* 'x' */)
1005 pval = p + 3, base = 16;
1006 else
1007 pval = p + 2, base = 10;
1008 len = OS__strtoent(base, pval, p + len, &val);
1009 if(len == -1) {
1010 /* Invalid charset. Just copy verbatim. */
1011 *buf++ = ch;
1012 continue;
1013 }
1014 if(!len || pval[len-1] != 0x3b) goto want_more;
1015 assert(val > 0);
1016 p += (pval - p) + len - 1; /* Advance past entref */
1017
1018 if(val < 0x80) {
1019 *buf++ = (char)val;
1020 } else if(val < 0x800) {
1021 *buf++ = 0xc0 | ((val >> 6));
1022 *buf++ = 0x80 | ((val & 0x3f));
1023 } else if(val < 0x10000) {
1024 *buf++ = 0xe0 | ((val >> 12));
1025 *buf++ = 0x80 | ((val >> 6) & 0x3f);
1026 *buf++ = 0x80 | ((val & 0x3f));
1027 } else if(val < 0x200000) {
1028 *buf++ = 0xf0 | ((val >> 18));
1029 *buf++ = 0x80 | ((val >> 12) & 0x3f);
1030 *buf++ = 0x80 | ((val >> 6) & 0x3f);
1031 *buf++ = 0x80 | ((val & 0x3f));
1032 } else if(val < 0x4000000) {
1033 *buf++ = 0xf8 | ((val >> 24));
1034 *buf++ = 0x80 | ((val >> 18) & 0x3f);
1035 *buf++ = 0x80 | ((val >> 12) & 0x3f);
1036 *buf++ = 0x80 | ((val >> 6) & 0x3f);
1037 *buf++ = 0x80 | ((val & 0x3f));
1038 } else {
1039 *buf++ = 0xfc | ((val >> 30) & 0x1);
1040 *buf++ = 0x80 | ((val >> 24) & 0x3f);
1041 *buf++ = 0x80 | ((val >> 18) & 0x3f);
1042 *buf++ = 0x80 | ((val >> 12) & 0x3f);
1043 *buf++ = 0x80 | ((val >> 6) & 0x3f);
1044 *buf++ = 0x80 | ((val & 0x3f));
1045 }
1046 } else {
1047 /*
1048 * Ugly, limited parsing of &amp; &gt; &lt;
1049 */
1050 char *sc = (char *)memchr(p, 0x3b, len > 5 ? 5 : len);
1051 if(!sc) goto want_more;
1052 if((sc - p) == 4
1053 && p[1] == 0x61 /* 'a' */
1054 && p[2] == 0x6d /* 'm' */
1055 && p[3] == 0x70 /* 'p' */) {
1056 *buf++ = 0x26;
1057 p = sc;
1058 continue;
1059 }
1060 if((sc - p) == 3) {
1061 if(p[1] == 0x6c) {
1062 *buf = 0x3c; /* '<' */
1063 } else if(p[1] == 0x67) {
1064 *buf = 0x3e; /* '>' */
1065 } else {
1066 /* Unsupported entity reference */
1067 *buf++ = ch;
1068 continue;
1069 }
1070 if(p[2] != 0x74) {
1071 /* Unsupported entity reference */
1072 *buf++ = ch;
1073 continue;
1074 }
1075 buf++;
1076 p = sc;
1077 continue;
1078 }
1079 /* Unsupported entity reference */
1080 *buf++ = ch;
1081 }
1082
1083 continue;
1084 want_more:
1085 if(have_more) {
1086 /*
1087 * We know that no more data (of the same type)
1088 * is coming. Copy the rest verbatim.
1089 */
1090 *buf++ = ch;
1091 continue;
1092 }
Lev Walkin0fab1a62005-03-09 22:19:25 +00001093 chunk_size = (p - (const char *)chunk_buf);
Lev Walkindc06f6b2004-10-20 15:50:55 +00001094 /* Processing stalled: need more data */
Lev Walkinbdaae772005-02-18 12:25:47 +00001095 break;
Lev Walkindc06f6b2004-10-20 15:50:55 +00001096 }
1097
1098 st->size = buf - st->buf;
1099 assert(st->size <= _ns);
1100 st->buf[st->size] = 0; /* Courtesy termination */
1101
1102 return chunk_size; /* Converted in full */
1103}
1104
1105/*
1106 * Decode OCTET STRING from the XML element's body.
1107 */
1108static asn_dec_rval_t
1109OCTET_STRING__decode_xer(asn_codec_ctx_t *opt_codec_ctx,
1110 asn_TYPE_descriptor_t *td, void **sptr,
Lev Walkin8c3b8542005-03-10 18:52:02 +00001111 const char *opt_mname, const void *buf_ptr, size_t size,
Lev Walkindc06f6b2004-10-20 15:50:55 +00001112 int (*opt_unexpected_tag_decoder)
Lev Walkin0fab1a62005-03-09 22:19:25 +00001113 (void *struct_ptr, const void *chunk_buf, size_t chunk_size),
Lev Walkindc06f6b2004-10-20 15:50:55 +00001114 ssize_t (*body_receiver)
Lev Walkin0fab1a62005-03-09 22:19:25 +00001115 (void *struct_ptr, const void *chunk_buf, size_t chunk_size,
Lev Walkindc06f6b2004-10-20 15:50:55 +00001116 int have_more)
1117) {
Lev Walkind5125642005-02-14 20:08:00 +00001118 OCTET_STRING_t *st = (OCTET_STRING_t *)*sptr;
Lev Walkindc06f6b2004-10-20 15:50:55 +00001119 asn_OCTET_STRING_specifics_t *specs = td->specifics
1120 ? (asn_OCTET_STRING_specifics_t *)td->specifics
1121 : &asn_DEF_OCTET_STRING_specs;
1122 const char *xml_tag = opt_mname ? opt_mname : td->xml_tag;
1123 asn_struct_ctx_t *ctx; /* Per-structure parser context */
Lev Walkinc61f3862005-02-14 17:21:22 +00001124 asn_dec_rval_t rval; /* Return value from the decoder */
1125 int st_allocated;
Lev Walkindc06f6b2004-10-20 15:50:55 +00001126
1127 /*
1128 * Create the string if does not exist.
1129 */
Lev Walkinc61f3862005-02-14 17:21:22 +00001130 if(!st) {
Lev Walkin8484ed82004-12-14 13:31:01 +00001131 st = (OCTET_STRING_t *)CALLOC(1, specs->struct_size);
Lev Walkin8484ed82004-12-14 13:31:01 +00001132 *sptr = (void *)st;
Lev Walkinc61f3862005-02-14 17:21:22 +00001133 if(!st) goto sta_failed;
1134 st_allocated = 1;
Lev Walkinbdaae772005-02-18 12:25:47 +00001135 } else {
1136 st_allocated = 0;
1137 }
Lev Walkinc61f3862005-02-14 17:21:22 +00001138 if(!st->buf) {
1139 /* This is separate from above section */
1140 st->buf = (uint8_t *)CALLOC(1, 1);
1141 if(!st->buf) {
1142 if(st_allocated) {
1143 *sptr = 0;
1144 goto stb_failed;
1145 } else {
1146 goto sta_failed;
1147 }
Lev Walkindc06f6b2004-10-20 15:50:55 +00001148 }
1149 }
1150
1151 /* Restore parsing context */
1152 ctx = (asn_struct_ctx_t *)(((char *)*sptr) + specs->ctx_offset);
1153
1154 return xer_decode_general(opt_codec_ctx, ctx, *sptr, xml_tag,
1155 buf_ptr, size, opt_unexpected_tag_decoder, body_receiver);
Lev Walkinc61f3862005-02-14 17:21:22 +00001156
1157stb_failed:
1158 FREEMEM(st);
1159sta_failed:
1160 rval.code = RC_FAIL;
1161 rval.consumed = 0;
1162 return rval;
Lev Walkindc06f6b2004-10-20 15:50:55 +00001163}
1164
1165/*
1166 * Decode OCTET STRING from the hexadecimal data.
1167 */
1168asn_dec_rval_t
1169OCTET_STRING_decode_xer_hex(asn_codec_ctx_t *opt_codec_ctx,
1170 asn_TYPE_descriptor_t *td, void **sptr,
Lev Walkin8c3b8542005-03-10 18:52:02 +00001171 const char *opt_mname, const void *buf_ptr, size_t size) {
Lev Walkindc06f6b2004-10-20 15:50:55 +00001172 return OCTET_STRING__decode_xer(opt_codec_ctx, td, sptr, opt_mname,
1173 buf_ptr, size, 0, OCTET_STRING__convert_hexadecimal);
1174}
1175
1176/*
1177 * Decode OCTET STRING from the binary (0/1) data.
1178 */
1179asn_dec_rval_t
1180OCTET_STRING_decode_xer_binary(asn_codec_ctx_t *opt_codec_ctx,
1181 asn_TYPE_descriptor_t *td, void **sptr,
Lev Walkin8c3b8542005-03-10 18:52:02 +00001182 const char *opt_mname, const void *buf_ptr, size_t size) {
Lev Walkindc06f6b2004-10-20 15:50:55 +00001183 return OCTET_STRING__decode_xer(opt_codec_ctx, td, sptr, opt_mname,
1184 buf_ptr, size, 0, OCTET_STRING__convert_binary);
1185}
1186
1187/*
1188 * Decode OCTET STRING from the string (ASCII/UTF-8) data.
1189 */
1190asn_dec_rval_t
1191OCTET_STRING_decode_xer_utf8(asn_codec_ctx_t *opt_codec_ctx,
1192 asn_TYPE_descriptor_t *td, void **sptr,
Lev Walkin8c3b8542005-03-10 18:52:02 +00001193 const char *opt_mname, const void *buf_ptr, size_t size) {
Lev Walkindc06f6b2004-10-20 15:50:55 +00001194 return OCTET_STRING__decode_xer(opt_codec_ctx, td, sptr, opt_mname,
1195 buf_ptr, size,
1196 OCTET_STRING__handle_control_chars,
1197 OCTET_STRING__convert_entrefs);
1198}
1199
Lev Walkin59b176e2005-11-26 11:25:14 +00001200asn_dec_rval_t
1201OCTET_STRING_decode_uper(asn_codec_ctx_t *opt_codec_ctx,
1202 asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints,
1203 void **sptr, asn_per_data_t *pd) {
1204
1205 asn_OCTET_STRING_specifics_t *specs = td->specifics
1206 ? (asn_OCTET_STRING_specifics_t *)td->specifics
1207 : &asn_DEF_OCTET_STRING_specs;
1208 asn_per_constraint_t *ct = constraints ? &constraints->size
1209 : (td->per_constraints
1210 ? &td->per_constraints->size
1211 : &asn_DEF_OCTET_STRING_constraint);
1212 asn_dec_rval_t rval = { RC_OK, 0 };
1213 BIT_STRING_t *st = (BIT_STRING_t *)*sptr;
1214 ssize_t consumed_myself = 0;
1215 int repeat;
1216 int unit_bits = (specs->subvariant != 1) * 7 + 1;
1217
1218 (void)opt_codec_ctx;
1219
1220 /*
1221 * Allocate the string.
1222 */
1223 if(!st) {
1224 st = (BIT_STRING_t *)(*sptr = CALLOC(1, specs->struct_size));
1225 if(!st) RETURN(RC_FAIL);
1226 }
1227
Lev Walkince676dd2005-12-20 22:34:55 +00001228 ASN_DEBUG("PER Decoding %s %ld .. %ld bits %d",
1229 ct->flags & APC_EXTENSIBLE ? "extensible" : "fixed",
1230 ct->lower_bound, ct->upper_bound, ct->effective_bits);
1231
Lev Walkin59b176e2005-11-26 11:25:14 +00001232 if(ct->flags & APC_EXTENSIBLE) {
1233 int inext = per_get_few_bits(pd, 1);
1234 if(inext < 0) RETURN(RC_FAIL);
1235 if(inext) ct = &asn_DEF_OCTET_STRING_constraint;
1236 consumed_myself = 0;
1237 }
1238
1239 if(ct->effective_bits >= 0
1240 && (!st->buf || st->size < ct->upper_bound)) {
1241 FREEMEM(st->buf);
1242 if(unit_bits == 1) {
1243 st->size = (ct->upper_bound + 7) >> 3;
1244 } else {
1245 st->size = ct->upper_bound;
1246 }
1247 st->buf = (uint8_t *)MALLOC(st->size + 1);
1248 if(!st->buf) { st->size = 0; RETURN(RC_FAIL); }
1249 }
1250
1251 /* X.691, #16.5: zero-length encoding */
1252 /* X.691, #16.6: short fixed length encoding (up to 2 octets) */
1253 /* X.691, #16.7: long fixed length encoding (up to 64K octets) */
1254 if(ct->effective_bits == 0) {
1255 int ret = per_get_many_bits(pd, st->buf, 0,
1256 unit_bits * ct->upper_bound);
1257 if(ret < 0) RETURN(RC_FAIL);
1258 consumed_myself += unit_bits * ct->upper_bound;
1259 st->buf[st->size] = 0;
1260 if(unit_bits == 1 && (ct->upper_bound & 0x7))
1261 st->bits_unused = 8 - (ct->upper_bound & 0x7);
1262 RETURN(RC_OK);
1263 }
1264
1265 st->size = 0;
1266 do {
1267 ssize_t len_bytes;
1268 ssize_t len_bits;
1269 void *p;
1270 int ret;
1271
1272 /* Get the PER length */
1273 len_bits = uper_get_length(pd, ct->effective_bits, &repeat);
1274 if(len_bits < 0) RETURN(RC_FAIL);
Lev Walkin1d5f0f22005-12-17 12:02:35 +00001275 len_bits += ct->lower_bound;
Lev Walkin59b176e2005-11-26 11:25:14 +00001276
Lev Walkin1d5f0f22005-12-17 12:02:35 +00001277 ASN_DEBUG("Got per length eb %ld, len %ld",
Lev Walkin1dc5b6f2005-12-21 10:08:27 +00001278 (long)ct->effective_bits, (long)len_bits);
Lev Walkin59b176e2005-11-26 11:25:14 +00001279 if(unit_bits == 1) {
1280 len_bytes = (len_bits + 7) >> 3;
1281 if(len_bits & 0x7)
1282 st->bits_unused = 8 - (len_bits & 0x7);
1283 /* len_bits be multiple of 16K if repeat is set */
1284 } else {
1285 len_bytes = len_bits;
1286 len_bits = len_bytes << 3;
1287 }
1288 p = REALLOC(st->buf, st->size + len_bytes + 1);
1289 if(!p) RETURN(RC_FAIL);
1290 st->buf = (uint8_t *)p;
1291
1292 ret = per_get_many_bits(pd, &st->buf[st->size], 0, len_bits);
1293 if(ret < 0) RETURN(RC_FAIL);
1294 st->size += len_bytes;
1295 } while(repeat);
1296 st->buf[st->size] = 0; /* nul-terminate */
1297
1298 return rval;
1299}
Lev Walkindc06f6b2004-10-20 15:50:55 +00001300
Lev Walkin523de9e2006-08-18 01:34:18 +00001301asn_enc_rval_t
1302OCTET_STRING_encode_uper(asn_TYPE_descriptor_t *td,
1303 asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) {
1304
1305 asn_OCTET_STRING_specifics_t *specs = td->specifics
1306 ? (asn_OCTET_STRING_specifics_t *)td->specifics
1307 : &asn_DEF_OCTET_STRING_specs;
1308 asn_per_constraint_t *ct = constraints ? &constraints->size
1309 : (td->per_constraints
1310 ? &td->per_constraints->size
1311 : &asn_DEF_OCTET_STRING_constraint);
1312 const BIT_STRING_t *st = (const BIT_STRING_t *)sptr;
1313 int unit_bits = (specs->subvariant != 1) * 7 + 1;
1314 asn_enc_rval_t er;
1315 int ct_extensible = ct->flags & APC_EXTENSIBLE;
1316 int inext = 0; /* Lies not within extension root */
1317 int sizeinunits = st->size;
1318 const uint8_t *buf;
1319 int ret;
1320
1321 if(!st || !st->buf)
1322 _ASN_ENCODE_FAILED;
1323
1324 if(unit_bits == 1) {
1325 ASN_DEBUG("BIT STRING of %d bytes, %d bits unused",
1326 sizeinunits, st->bits_unused);
1327 sizeinunits = sizeinunits * 8 - (st->bits_unused & 0x07);
1328 }
1329
1330 ASN_DEBUG("Encoding %s into %d units",
1331 td->name, sizeinunits);
1332
1333 /* Figure out wheter size lies within PER visible consrtaint */
1334
1335 if(ct->effective_bits >= 0) {
1336 if(sizeinunits < ct->lower_bound
1337 || sizeinunits > ct->upper_bound) {
1338 if(ct_extensible) {
1339 ct = &asn_DEF_OCTET_STRING_constraint;
1340 inext = 1;
1341 } else
1342 _ASN_ENCODE_FAILED;
1343 }
1344 } else {
1345 inext = 0;
1346 }
1347
1348 if(ct_extensible) {
1349 /* Declare whether length is [not] within extension root */
1350 if(per_put_few_bits(po, inext, 1))
1351 _ASN_ENCODE_FAILED;
1352 }
1353
1354 /* X.691, #16.5: zero-length encoding */
1355 /* X.691, #16.6: short fixed length encoding (up to 2 octets) */
1356 /* X.691, #16.7: long fixed length encoding (up to 64K octets) */
1357 if(ct->effective_bits >= 0) {
1358 ASN_DEBUG("Encoding %d bytes (%ld), length in %d bits",
1359 st->size, sizeinunits - ct->lower_bound,
1360 ct->effective_bits);
1361 ret = per_put_few_bits(po, sizeinunits - ct->lower_bound,
1362 ct->effective_bits);
1363 if(ret) _ASN_ENCODE_FAILED;
1364 ret = per_put_many_bits(po, st->buf, sizeinunits);
1365 if(ret) _ASN_ENCODE_FAILED;
1366 _ASN_ENCODED_OK(er);
1367 }
1368
1369 ASN_DEBUG("Encoding %d bytes", st->size);
1370
1371 if(sizeinunits == 0) {
1372 if(uper_put_length(po, 0))
1373 _ASN_ENCODE_FAILED;
1374 _ASN_ENCODED_OK(er);
1375 }
1376
1377 buf = st->buf;
1378 while(sizeinunits) {
1379 ssize_t maySave = uper_put_length(po, sizeinunits);
1380 if(maySave < 0) _ASN_ENCODE_FAILED;
1381
1382 ASN_DEBUG("Encoding %d of %d", maySave, sizeinunits);
1383
1384 ret = per_put_many_bits(po, buf, maySave);
1385 if(ret) _ASN_ENCODE_FAILED;
1386
1387 if(unit_bits == 1)
1388 buf += maySave >> 3;
1389 else
1390 buf += maySave;
1391 sizeinunits -= maySave;
1392 assert(!(maySave & 0x07) || !sizeinunits);
1393 }
1394
1395 _ASN_ENCODED_OK(er);
1396}
1397
Lev Walkinf15320b2004-06-03 03:38:44 +00001398int
Lev Walkinde4825d2004-09-29 13:20:14 +00001399OCTET_STRING_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel,
Lev Walkinf15320b2004-06-03 03:38:44 +00001400 asn_app_consume_bytes_f *cb, void *app_key) {
Lev Walkin4d9528c2004-08-11 08:10:13 +00001401 static const char *h2c = "0123456789ABCDEF";
Lev Walkinc2346572004-08-11 09:07:36 +00001402 const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr;
Lev Walkinf15320b2004-06-03 03:38:44 +00001403 char scratch[16 * 3 + 4];
1404 char *p = scratch;
1405 uint8_t *buf;
1406 uint8_t *end;
1407 size_t i;
Lev Walkinf15320b2004-06-03 03:38:44 +00001408
Lev Walkind9bd7752004-06-05 08:17:50 +00001409 (void)td; /* Unused argument */
1410
Lev Walkin8e8078a2004-09-26 13:10:40 +00001411 if(!st || !st->buf) return (cb("<absent>", 8, app_key) < 0) ? -1 : 0;
Lev Walkinf15320b2004-06-03 03:38:44 +00001412
1413 /*
1414 * Dump the contents of the buffer in hexadecimal.
1415 */
1416 buf = st->buf;
1417 end = buf + st->size;
1418 for(i = 0; buf < end; buf++, i++) {
1419 if(!(i % 16) && (i || st->size > 16)) {
Lev Walkin8e8078a2004-09-26 13:10:40 +00001420 if(cb(scratch, p - scratch, app_key) < 0)
Lev Walkinf15320b2004-06-03 03:38:44 +00001421 return -1;
Lev Walkin8e8078a2004-09-26 13:10:40 +00001422 _i_INDENT(1);
Lev Walkinf15320b2004-06-03 03:38:44 +00001423 p = scratch;
1424 }
1425 *p++ = h2c[(*buf >> 4) & 0x0F];
1426 *p++ = h2c[*buf & 0x0F];
Lev Walkina9cc46e2004-09-22 16:06:28 +00001427 *p++ = 0x20;
Lev Walkinf15320b2004-06-03 03:38:44 +00001428 }
1429
Lev Walkincc6a9102004-09-23 22:06:26 +00001430 if(p > scratch) {
1431 p--; /* Remove the tail space */
Lev Walkin8e8078a2004-09-26 13:10:40 +00001432 if(cb(scratch, p - scratch, app_key) < 0)
Lev Walkincc6a9102004-09-23 22:06:26 +00001433 return -1;
1434 }
1435
1436 return 0;
Lev Walkinf15320b2004-06-03 03:38:44 +00001437}
1438
1439int
Lev Walkindc06f6b2004-10-20 15:50:55 +00001440OCTET_STRING_print_utf8(asn_TYPE_descriptor_t *td, const void *sptr,
Lev Walkinf15320b2004-06-03 03:38:44 +00001441 int ilevel, asn_app_consume_bytes_f *cb, void *app_key) {
Lev Walkinc2346572004-08-11 09:07:36 +00001442 const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr;
Lev Walkinf15320b2004-06-03 03:38:44 +00001443
Lev Walkind9bd7752004-06-05 08:17:50 +00001444 (void)td; /* Unused argument */
1445 (void)ilevel; /* Unused argument */
1446
Lev Walkinf15320b2004-06-03 03:38:44 +00001447 if(st && st->buf) {
Lev Walkin8e8078a2004-09-26 13:10:40 +00001448 return (cb(st->buf, st->size, app_key) < 0) ? -1 : 0;
Lev Walkinf15320b2004-06-03 03:38:44 +00001449 } else {
Lev Walkin8e8078a2004-09-26 13:10:40 +00001450 return (cb("<absent>", 8, app_key) < 0) ? -1 : 0;
Lev Walkinf15320b2004-06-03 03:38:44 +00001451 }
1452}
1453
1454void
Lev Walkinde4825d2004-09-29 13:20:14 +00001455OCTET_STRING_free(asn_TYPE_descriptor_t *td, void *sptr, int contents_only) {
Lev Walkinc2346572004-08-11 09:07:36 +00001456 OCTET_STRING_t *st = (OCTET_STRING_t *)sptr;
Lev Walkinbbd93252004-10-12 05:57:23 +00001457 asn_OCTET_STRING_specifics_t *specs = td->specifics
Lev Walkindc06f6b2004-10-20 15:50:55 +00001458 ? (asn_OCTET_STRING_specifics_t *)td->specifics
1459 : &asn_DEF_OCTET_STRING_specs;
Lev Walkinbbd93252004-10-12 05:57:23 +00001460 asn_struct_ctx_t *ctx = (asn_struct_ctx_t *)
1461 ((char *)st + specs->ctx_offset);
Lev Walkinb54577a2004-11-08 10:47:12 +00001462 struct _stack *stck;
Lev Walkinf15320b2004-06-03 03:38:44 +00001463
1464 if(!td || !st)
1465 return;
1466
1467 ASN_DEBUG("Freeing %s as OCTET STRING", td->name);
1468
1469 if(st->buf) {
1470 FREEMEM(st->buf);
1471 }
1472
1473 /*
1474 * Remove decode-time stack.
1475 */
Lev Walkinb54577a2004-11-08 10:47:12 +00001476 stck = (struct _stack *)ctx->ptr;
Lev Walkinf15320b2004-06-03 03:38:44 +00001477 if(stck) {
1478 while(stck->tail) {
1479 struct _stack_el *sel = stck->tail;
1480 stck->tail = sel->prev;
1481 FREEMEM(sel);
1482 }
1483 FREEMEM(stck);
1484 }
1485
1486 if(!contents_only) {
1487 FREEMEM(st);
1488 }
1489}
1490
1491/*
1492 * Conversion routines.
1493 */
1494int
1495OCTET_STRING_fromBuf(OCTET_STRING_t *st, const char *str, int len) {
1496 void *buf;
1497
1498 if(st == 0 || (str == 0 && len)) {
1499 errno = EINVAL;
1500 return -1;
1501 }
1502
1503 /*
1504 * Clear the OCTET STRING.
1505 */
1506 if(str == NULL) {
Lev Walkin7b284812005-12-17 11:43:25 +00001507 FREEMEM(st->buf);
1508 st->buf = 0;
Lev Walkinf15320b2004-06-03 03:38:44 +00001509 st->size = 0;
1510 return 0;
1511 }
1512
1513 /* Determine the original string size, if not explicitly given */
1514 if(len < 0)
1515 len = strlen(str);
1516
1517 /* Allocate and fill the memory */
1518 buf = MALLOC(len + 1);
Lev Walkin7b284812005-12-17 11:43:25 +00001519 if(buf == NULL)
Lev Walkinf15320b2004-06-03 03:38:44 +00001520 return -1;
Lev Walkinf15320b2004-06-03 03:38:44 +00001521
1522 memcpy(buf, str, len);
Lev Walkin7b284812005-12-17 11:43:25 +00001523 ((uint8_t *)buf)[len] = '\0'; /* Couldn't use memcpy(len+1)! */
1524 FREEMEM(st->buf);
1525 st->buf = (uint8_t *)buf;
1526 st->size = len;
Lev Walkinf15320b2004-06-03 03:38:44 +00001527
1528 return 0;
1529}
1530
1531OCTET_STRING_t *
Lev Walkinbbd93252004-10-12 05:57:23 +00001532OCTET_STRING_new_fromBuf(asn_TYPE_descriptor_t *td, const char *str, int len) {
1533 asn_OCTET_STRING_specifics_t *specs = td->specifics
Lev Walkindc06f6b2004-10-20 15:50:55 +00001534 ? (asn_OCTET_STRING_specifics_t *)td->specifics
1535 : &asn_DEF_OCTET_STRING_specs;
Lev Walkinf15320b2004-06-03 03:38:44 +00001536 OCTET_STRING_t *st;
1537
Lev Walkinbbd93252004-10-12 05:57:23 +00001538 st = (OCTET_STRING_t *)CALLOC(1, specs->struct_size);
Lev Walkinf15320b2004-06-03 03:38:44 +00001539 if(st && str && OCTET_STRING_fromBuf(st, str, len)) {
1540 free(st);
1541 st = NULL;
1542 }
1543
1544 return st;
1545}
1546