Adding initial code jy.oak@samsung.com
[ric-app/kpimon.git] / asn1c_defs / all-defs / OCTET_STRING.c
1 /*-\r
2  * Copyright (c) 2003-2017 Lev Walkin <vlm@lionet.info>.\r
3  * All rights reserved.\r
4  * Redistribution and modifications are permitted subject to BSD license.\r
5  */\r
6 #include <asn_internal.h>\r
7 #include <OCTET_STRING.h>\r
8 #include <BIT_STRING.h> /* for .bits_unused member */\r
9 #include <errno.h>\r
10 \r
11 /*\r
12  * OCTET STRING basic type description.\r
13  */\r
14 static const ber_tlv_tag_t asn_DEF_OCTET_STRING_tags[] = {\r
15         (ASN_TAG_CLASS_UNIVERSAL | (4 << 2))\r
16 };\r
17 asn_OCTET_STRING_specifics_t asn_SPC_OCTET_STRING_specs = {\r
18         sizeof(OCTET_STRING_t),\r
19         offsetof(OCTET_STRING_t, _asn_ctx),\r
20         ASN_OSUBV_STR\r
21 };\r
22 \r
23 asn_TYPE_operation_t asn_OP_OCTET_STRING = {\r
24         OCTET_STRING_free,\r
25         OCTET_STRING_print,     /* OCTET STRING generally means a non-ascii sequence */\r
26         OCTET_STRING_compare,\r
27         OCTET_STRING_decode_ber,\r
28         OCTET_STRING_encode_der,\r
29         OCTET_STRING_decode_xer_hex,\r
30         OCTET_STRING_encode_xer,\r
31 #ifdef  ASN_DISABLE_OER_SUPPORT\r
32         0,\r
33         0,\r
34 #else\r
35         OCTET_STRING_decode_oer,\r
36         OCTET_STRING_encode_oer,\r
37 #endif  /* ASN_DISABLE_OER_SUPPORT */\r
38 #ifdef  ASN_DISABLE_PER_SUPPORT\r
39         0,\r
40         0,\r
41         0,\r
42         0,\r
43 #else\r
44         OCTET_STRING_decode_uper,       /* Unaligned PER decoder */\r
45         OCTET_STRING_encode_uper,       /* Unaligned PER encoder */\r
46         OCTET_STRING_decode_aper,       /* Aligned PER decoder */\r
47         OCTET_STRING_encode_aper,       /* Aligned PER encoder */\r
48 #endif  /* ASN_DISABLE_PER_SUPPORT */\r
49         OCTET_STRING_random_fill,\r
50         0       /* Use generic outmost tag fetcher */\r
51 };\r
52 asn_TYPE_descriptor_t asn_DEF_OCTET_STRING = {\r
53         "OCTET STRING",         /* Canonical name */\r
54         "OCTET_STRING",         /* XML tag name */\r
55         &asn_OP_OCTET_STRING,\r
56         asn_DEF_OCTET_STRING_tags,\r
57         sizeof(asn_DEF_OCTET_STRING_tags)\r
58           / sizeof(asn_DEF_OCTET_STRING_tags[0]),\r
59         asn_DEF_OCTET_STRING_tags,      /* Same as above */\r
60         sizeof(asn_DEF_OCTET_STRING_tags)\r
61           / sizeof(asn_DEF_OCTET_STRING_tags[0]),\r
62         { 0, 0, asn_generic_no_constraint },\r
63         0, 0,   /* No members */\r
64         &asn_SPC_OCTET_STRING_specs\r
65 };\r
66 \r
67 #undef  _CH_PHASE\r
68 #undef  NEXT_PHASE\r
69 #undef  PREV_PHASE\r
70 #define _CH_PHASE(ctx, inc) do {                                        \\r
71                 if(ctx->phase == 0)                                     \\r
72                         ctx->context = 0;                               \\r
73                 ctx->phase += inc;                                      \\r
74         } while(0)\r
75 #define NEXT_PHASE(ctx) _CH_PHASE(ctx, +1)\r
76 #define PREV_PHASE(ctx) _CH_PHASE(ctx, -1)\r
77 \r
78 #undef  ADVANCE\r
79 #define ADVANCE(num_bytes)      do {                                    \\r
80                 size_t num = (num_bytes);                               \\r
81                 buf_ptr = ((const char *)buf_ptr) + num;                \\r
82                 size -= num;                                            \\r
83                 consumed_myself += num;                                 \\r
84         } while(0)\r
85 \r
86 #undef  RETURN\r
87 #define RETURN(_code)   do {                                            \\r
88                 asn_dec_rval_t tmprval;                                 \\r
89                 tmprval.code = _code;                                   \\r
90                 tmprval.consumed = consumed_myself;                     \\r
91                 return tmprval;                                         \\r
92         } while(0)\r
93 \r
94 #undef  APPEND\r
95 #define APPEND(bufptr, bufsize) do {                                    \\r
96                 size_t _bs = (bufsize);         /* Append size */       \\r
97                 size_t _ns = ctx->context;      /* Allocated now */     \\r
98                 size_t _es = st->size + _bs;    /* Expected size */     \\r
99                 /* int is really a typeof(st->size): */                 \\r
100                 if((int)_es < 0) RETURN(RC_FAIL);                       \\r
101                 if(_ns <= _es) {                                        \\r
102                         void *ptr;                                      \\r
103                         /* Be nice and round to the memory allocator */ \\r
104                         do { _ns = _ns ? _ns << 1 : 16; }               \\r
105                             while(_ns <= _es);                          \\r
106                         /* int is really a typeof(st->size): */         \\r
107                         if((int)_ns < 0) RETURN(RC_FAIL);               \\r
108                         ptr = REALLOC(st->buf, _ns);                    \\r
109                         if(ptr) {                                       \\r
110                                 st->buf = (uint8_t *)ptr;               \\r
111                                 ctx->context = _ns;                     \\r
112                         } else {                                        \\r
113                                 RETURN(RC_FAIL);                        \\r
114                         }                                               \\r
115                         ASN_DEBUG("Reallocating into %ld", (long)_ns);  \\r
116                 }                                                       \\r
117                 memcpy(st->buf + st->size, bufptr, _bs);                \\r
118                 /* Convenient nul-termination */                        \\r
119                 st->buf[_es] = '\0';                                    \\r
120                 st->size = _es;                                         \\r
121         } while(0)\r
122 \r
123 /*\r
124  * The main reason why ASN.1 is still alive is that too much time and effort\r
125  * is necessary for learning it more or less adequately, thus creating a gut\r
126  * necessity to demonstrate that aquired skill everywhere afterwards.\r
127  * No, I am not going to explain what the following stuff is.\r
128  */\r
129 struct _stack_el {\r
130     ber_tlv_len_t left;     /* What's left to read (or -1) */\r
131     ber_tlv_len_t got;      /* What was actually processed */\r
132     unsigned cont_level;    /* Depth of subcontainment */\r
133     int want_nulls;         /* Want null "end of content" octets? */\r
134     int bits_chopped;       /* Flag in BIT STRING mode */\r
135     ber_tlv_tag_t tag;      /* For debugging purposes */\r
136     struct _stack_el *prev;\r
137     struct _stack_el *next;\r
138 };\r
139 struct _stack {\r
140         struct _stack_el *tail;\r
141         struct _stack_el *cur_ptr;\r
142 };\r
143 \r
144 static struct _stack_el *\r
145 OS__add_stack_el(struct _stack *st) {\r
146         struct _stack_el *nel;\r
147 \r
148         /*\r
149          * Reuse the old stack frame or allocate a new one.\r
150          */\r
151         if(st->cur_ptr && st->cur_ptr->next) {\r
152                 nel = st->cur_ptr->next;\r
153                 nel->bits_chopped = 0;\r
154                 nel->got = 0;\r
155                 /* Retain the nel->cont_level, it's correct. */\r
156         } else {\r
157                 nel = (struct _stack_el *)CALLOC(1, sizeof(struct _stack_el));\r
158                 if(nel == NULL)\r
159                         return NULL;\r
160         \r
161                 if(st->tail) {\r
162                         /* Increase a subcontainment depth */\r
163                         nel->cont_level = st->tail->cont_level + 1;\r
164                         st->tail->next = nel;\r
165                 }\r
166                 nel->prev = st->tail;\r
167                 st->tail = nel;\r
168         }\r
169 \r
170         st->cur_ptr = nel;\r
171 \r
172         return nel;\r
173 }\r
174 \r
175 static struct _stack *\r
176 _new_stack(void) {\r
177         return (struct _stack *)CALLOC(1, sizeof(struct _stack));\r
178 }\r
179 \r
180 /*\r
181  * Decode OCTET STRING type.\r
182  */\r
183 asn_dec_rval_t\r
184 OCTET_STRING_decode_ber(const asn_codec_ctx_t *opt_codec_ctx,\r
185                         const asn_TYPE_descriptor_t *td, void **sptr,\r
186                         const void *buf_ptr, size_t size, int tag_mode) {\r
187     const asn_OCTET_STRING_specifics_t *specs = td->specifics\r
188                                 ? (const asn_OCTET_STRING_specifics_t *)td->specifics\r
189                                 : &asn_SPC_OCTET_STRING_specs;\r
190         BIT_STRING_t *st = (BIT_STRING_t *)*sptr;\r
191         asn_dec_rval_t rval;\r
192         asn_struct_ctx_t *ctx;\r
193         ssize_t consumed_myself = 0;\r
194         struct _stack *stck;            /* Expectations stack structure */\r
195         struct _stack_el *sel = 0;      /* Stack element */\r
196         int tlv_constr;\r
197         enum asn_OS_Subvariant type_variant = specs->subvariant;\r
198 \r
199         ASN_DEBUG("Decoding %s as %s (frame %ld)",\r
200                 td->name,\r
201                 (type_variant == ASN_OSUBV_STR) ?\r
202                         "OCTET STRING" : "OS-SpecialCase",\r
203                 (long)size);\r
204 \r
205         /*\r
206          * Create the string if does not exist.\r
207          */\r
208         if(st == NULL) {\r
209                 st = (BIT_STRING_t *)(*sptr = CALLOC(1, specs->struct_size));\r
210                 if(st == NULL) RETURN(RC_FAIL);\r
211         }\r
212 \r
213         /* Restore parsing context */\r
214         ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset);\r
215 \r
216         switch(ctx->phase) {\r
217         case 0:\r
218                 /*\r
219                  * Check tags.\r
220                  */\r
221                 rval = ber_check_tags(opt_codec_ctx, td, ctx,\r
222                         buf_ptr, size, tag_mode, -1,\r
223                         &ctx->left, &tlv_constr);\r
224                 if(rval.code != RC_OK)\r
225                         return rval;\r
226 \r
227                 if(tlv_constr) {\r
228                         /*\r
229                          * Complex operation, requires stack of expectations.\r
230                          */\r
231                         ctx->ptr = _new_stack();\r
232                         if(!ctx->ptr) {\r
233                                 RETURN(RC_FAIL);\r
234                         }\r
235                 } else {\r
236                         /*\r
237                          * Jump into stackless primitive decoding.\r
238                          */\r
239                         _CH_PHASE(ctx, 3);\r
240                         if(type_variant == ASN_OSUBV_ANY && tag_mode != 1)\r
241                                 APPEND(buf_ptr, rval.consumed);\r
242                         ADVANCE(rval.consumed);\r
243                         goto phase3;\r
244                 }\r
245 \r
246                 NEXT_PHASE(ctx);\r
247                 /* Fall through */\r
248         case 1:\r
249         phase1:\r
250                 /*\r
251                  * Fill the stack with expectations.\r
252                  */\r
253                 stck = (struct _stack *)ctx->ptr;\r
254                 sel = stck->cur_ptr;\r
255           do {\r
256                 ber_tlv_tag_t tlv_tag;\r
257                 ber_tlv_len_t tlv_len;\r
258                 ber_tlv_tag_t expected_tag;\r
259                 ssize_t tl, ll, tlvl;\r
260                                 /* This one works even if (sel->left == -1) */\r
261                 size_t Left = ((!sel||(size_t)sel->left >= size)\r
262                                         ?size:(size_t)sel->left);\r
263 \r
264 \r
265                 ASN_DEBUG("%p, s->l=%ld, s->wn=%ld, s->g=%ld\n", (void *)sel,\r
266                         (long)(sel?sel->left:0),\r
267                         (long)(sel?sel->want_nulls:0),\r
268                         (long)(sel?sel->got:0)\r
269                 );\r
270                 if(sel && sel->left <= 0 && sel->want_nulls == 0) {\r
271                         if(sel->prev) {\r
272                                 struct _stack_el *prev = sel->prev;\r
273                                 if(prev->left != -1) {\r
274                                         if(prev->left < sel->got)\r
275                                                 RETURN(RC_FAIL);\r
276                                         prev->left -= sel->got;\r
277                                 }\r
278                                 prev->got += sel->got;\r
279                                 sel = stck->cur_ptr = prev;\r
280                                 if(!sel) break;\r
281                                 tlv_constr = 1;\r
282                                 continue;\r
283                         } else {\r
284                                 sel = stck->cur_ptr = 0;\r
285                                 break;  /* Nothing to wait */\r
286                         }\r
287                 }\r
288 \r
289                 tl = ber_fetch_tag(buf_ptr, Left, &tlv_tag);\r
290                 ASN_DEBUG("fetch tag(size=%ld,L=%ld), %sstack, left=%ld, wn=%ld, tl=%ld",\r
291                         (long)size, (long)Left, sel?"":"!",\r
292                         (long)(sel?sel->left:0),\r
293                         (long)(sel?sel->want_nulls:0),\r
294                         (long)tl);\r
295                 switch(tl) {\r
296                 case -1: RETURN(RC_FAIL);\r
297                 case 0: RETURN(RC_WMORE);\r
298                 }\r
299 \r
300                 tlv_constr = BER_TLV_CONSTRUCTED(buf_ptr);\r
301 \r
302                 ll = ber_fetch_length(tlv_constr,\r
303                                 (const char *)buf_ptr + tl,Left - tl,&tlv_len);\r
304                 ASN_DEBUG("Got tag=%s, tc=%d, left=%ld, tl=%ld, len=%ld, ll=%ld",\r
305                         ber_tlv_tag_string(tlv_tag), tlv_constr,\r
306                                 (long)Left, (long)tl, (long)tlv_len, (long)ll);\r
307                 switch(ll) {\r
308                 case -1: RETURN(RC_FAIL);\r
309                 case 0: RETURN(RC_WMORE);\r
310                 }\r
311 \r
312                 if(sel && sel->want_nulls\r
313                         && ((const uint8_t *)buf_ptr)[0] == 0\r
314                         && ((const uint8_t *)buf_ptr)[1] == 0)\r
315                 {\r
316 \r
317                         ASN_DEBUG("Eat EOC; wn=%d--", sel->want_nulls);\r
318 \r
319                         if(type_variant == ASN_OSUBV_ANY\r
320                         && (tag_mode != 1 || sel->cont_level))\r
321                                 APPEND("\0\0", 2);\r
322 \r
323                         ADVANCE(2);\r
324                         sel->got += 2;\r
325                         if(sel->left != -1) {\r
326                                 sel->left -= 2; /* assert(sel->left >= 2) */\r
327                         }\r
328 \r
329                         sel->want_nulls--;\r
330                         if(sel->want_nulls == 0) {\r
331                                 /* Move to the next expectation */\r
332                                 sel->left = 0;\r
333                                 tlv_constr = 1;\r
334                         }\r
335 \r
336                         continue;\r
337                 }\r
338 \r
339                 /*\r
340                  * Set up expected tags,\r
341                  * depending on ASN.1 type being decoded.\r
342                  */\r
343                 switch(type_variant) {\r
344                 case ASN_OSUBV_BIT:\r
345                         /* X.690: 8.6.4.1, NOTE 2 */\r
346                         /* Fall through */\r
347                 case ASN_OSUBV_STR:\r
348                 default:\r
349                         if(sel) {\r
350                                 unsigned level = sel->cont_level;\r
351                                 if(level < td->all_tags_count) {\r
352                                         expected_tag = td->all_tags[level];\r
353                                         break;\r
354                                 } else if(td->all_tags_count) {\r
355                                         expected_tag = td->all_tags\r
356                                                 [td->all_tags_count - 1];\r
357                                         break;\r
358                                 }\r
359                                 /* else, Fall through */\r
360                         }\r
361                         /* Fall through */\r
362                 case ASN_OSUBV_ANY:\r
363                         expected_tag = tlv_tag;\r
364                         break;\r
365                 }\r
366 \r
367 \r
368                 if(tlv_tag != expected_tag) {\r
369                         char buf[2][32];\r
370                         ber_tlv_tag_snprint(tlv_tag,\r
371                                 buf[0], sizeof(buf[0]));\r
372                         ber_tlv_tag_snprint(td->tags[td->tags_count-1],\r
373                                 buf[1], sizeof(buf[1]));\r
374                         ASN_DEBUG("Tag does not match expectation: %s != %s",\r
375                                 buf[0], buf[1]);\r
376                         RETURN(RC_FAIL);\r
377                 }\r
378 \r
379                 tlvl = tl + ll; /* Combined length of T and L encoding */\r
380                 if((tlv_len + tlvl) < 0) {\r
381                         /* tlv_len value is too big */\r
382                         ASN_DEBUG("TLV encoding + length (%ld) is too big",\r
383                                 (long)tlv_len);\r
384                         RETURN(RC_FAIL);\r
385                 }\r
386 \r
387                 /*\r
388                  * Append a new expectation.\r
389                  */\r
390                 sel = OS__add_stack_el(stck);\r
391                 if(!sel) RETURN(RC_FAIL);\r
392 \r
393                 sel->tag = tlv_tag;\r
394 \r
395                 sel->want_nulls = (tlv_len==-1);\r
396                 if(sel->prev && sel->prev->left != -1) {\r
397                         /* Check that the parent frame is big enough */\r
398                         if(sel->prev->left < tlvl + (tlv_len==-1?0:tlv_len))\r
399                                 RETURN(RC_FAIL);\r
400                         if(tlv_len == -1)\r
401                                 sel->left = sel->prev->left - tlvl;\r
402                         else\r
403                                 sel->left = tlv_len;\r
404                 } else {\r
405                         sel->left = tlv_len;\r
406                 }\r
407                 if(type_variant == ASN_OSUBV_ANY\r
408                 && (tag_mode != 1 || sel->cont_level))\r
409                         APPEND(buf_ptr, tlvl);\r
410                 sel->got += tlvl;\r
411                 ADVANCE(tlvl);\r
412 \r
413                 ASN_DEBUG("+EXPECT2 got=%ld left=%ld, wn=%d, clvl=%u",\r
414                         (long)sel->got, (long)sel->left,\r
415                         sel->want_nulls, sel->cont_level);\r
416 \r
417           } while(tlv_constr);\r
418                 if(sel == NULL) {\r
419                         /* Finished operation, "phase out" */\r
420                         ASN_DEBUG("Phase out");\r
421                         _CH_PHASE(ctx, +3);\r
422                         break;\r
423                 }\r
424 \r
425                 NEXT_PHASE(ctx);\r
426                 /* Fall through */\r
427         case 2:\r
428                 stck = (struct _stack *)ctx->ptr;\r
429                 sel = stck->cur_ptr;\r
430                 ASN_DEBUG("Phase 2: Need %ld bytes, size=%ld, alrg=%ld, wn=%d",\r
431                         (long)sel->left, (long)size, (long)sel->got,\r
432                                 sel->want_nulls);\r
433             {\r
434                 ber_tlv_len_t len;\r
435 \r
436                 assert(sel->left >= 0);\r
437 \r
438                 len = ((ber_tlv_len_t)size < sel->left)\r
439                                 ? (ber_tlv_len_t)size : sel->left;\r
440                 if(len > 0) {\r
441                         if(type_variant == ASN_OSUBV_BIT\r
442                         && sel->bits_chopped == 0) {\r
443                                 /* Put the unused-bits-octet away */\r
444                                 st->bits_unused = *(const uint8_t *)buf_ptr;\r
445                                 APPEND(((const char *)buf_ptr+1), (len - 1));\r
446                                 sel->bits_chopped = 1;\r
447                         } else {\r
448                                 APPEND(buf_ptr, len);\r
449                         }\r
450                         ADVANCE(len);\r
451                         sel->left -= len;\r
452                         sel->got += len;\r
453                 }\r
454 \r
455                 if(sel->left) {\r
456                         ASN_DEBUG("OS left %ld, size = %ld, wn=%d\n",\r
457                                 (long)sel->left, (long)size, sel->want_nulls);\r
458                         RETURN(RC_WMORE);\r
459                 }\r
460 \r
461                 PREV_PHASE(ctx);\r
462                 goto phase1;\r
463             }\r
464                 break;\r
465         case 3:\r
466         phase3:\r
467                 /*\r
468                  * Primitive form, no stack required.\r
469                  */\r
470                 assert(ctx->left >= 0);\r
471 \r
472                 if(size < (size_t)ctx->left) {\r
473                         if(!size) RETURN(RC_WMORE);\r
474                         if(type_variant == ASN_OSUBV_BIT && !ctx->context) {\r
475                                 st->bits_unused = *(const uint8_t *)buf_ptr;\r
476                                 ctx->left--;\r
477                                 ADVANCE(1);\r
478                         }\r
479                         APPEND(buf_ptr, size);\r
480                         assert(ctx->context > 0);\r
481                         ctx->left -= size;\r
482                         ADVANCE(size);\r
483                         RETURN(RC_WMORE);\r
484                 } else {\r
485                         if(type_variant == ASN_OSUBV_BIT\r
486                         && !ctx->context && ctx->left) {\r
487                                 st->bits_unused = *(const uint8_t *)buf_ptr;\r
488                                 ctx->left--;\r
489                                 ADVANCE(1);\r
490                         }\r
491                         APPEND(buf_ptr, ctx->left);\r
492                         ADVANCE(ctx->left);\r
493                         ctx->left = 0;\r
494 \r
495                         NEXT_PHASE(ctx);\r
496                 }\r
497                 break;\r
498         }\r
499 \r
500         if(sel) {\r
501                 ASN_DEBUG("3sel p=%p, wn=%d, l=%ld, g=%ld, size=%ld",\r
502                         (void *)sel->prev, sel->want_nulls,\r
503                         (long)sel->left, (long)sel->got, (long)size);\r
504                 if(sel->prev || sel->want_nulls > 1 || sel->left > 0) {\r
505                         RETURN(RC_WMORE);\r
506                 }\r
507         }\r
508 \r
509         /*\r
510          * BIT STRING-specific processing.\r
511          */\r
512         if(type_variant == ASN_OSUBV_BIT) {\r
513         if(st->size) {\r
514                         if(st->bits_unused < 0 || st->bits_unused > 7) {\r
515                                 RETURN(RC_FAIL);\r
516                         }\r
517                         /* Finalize BIT STRING: zero out unused bits. */\r
518                         st->buf[st->size-1] &= 0xff << st->bits_unused;\r
519                 } else {\r
520                         if(st->bits_unused) {\r
521                                 RETURN(RC_FAIL);\r
522                         }\r
523                 }\r
524         }\r
525 \r
526         ASN_DEBUG("Took %ld bytes to encode %s: [%s]:%ld",\r
527                 (long)consumed_myself, td->name,\r
528                 (type_variant == ASN_OSUBV_STR) ? (char *)st->buf : "<data>",\r
529                 (long)st->size);\r
530 \r
531 \r
532         RETURN(RC_OK);\r
533 }\r
534 \r
535 /*\r
536  * Encode OCTET STRING type using DER.\r
537  */\r
538 asn_enc_rval_t\r
539 OCTET_STRING_encode_der(const asn_TYPE_descriptor_t *td, const void *sptr,\r
540                         int tag_mode, ber_tlv_tag_t tag,\r
541                         asn_app_consume_bytes_f *cb, void *app_key) {\r
542     asn_enc_rval_t er = { 0, 0, 0 };\r
543         const asn_OCTET_STRING_specifics_t *specs = td->specifics\r
544                                 ? (const asn_OCTET_STRING_specifics_t *)td->specifics\r
545                                 : &asn_SPC_OCTET_STRING_specs;\r
546         const BIT_STRING_t *st = (const BIT_STRING_t *)sptr;\r
547         enum asn_OS_Subvariant type_variant = specs->subvariant;\r
548         int fix_last_byte = 0;\r
549 \r
550         ASN_DEBUG("%s %s as OCTET STRING",\r
551                 cb?"Estimating":"Encoding", td->name);\r
552 \r
553         /*\r
554          * Write tags.\r
555          */\r
556         if(type_variant != ASN_OSUBV_ANY || tag_mode == 1) {\r
557                 er.encoded = der_write_tags(td,\r
558                                 (type_variant == ASN_OSUBV_BIT) + st->size,\r
559                         tag_mode, type_variant == ASN_OSUBV_ANY, tag,\r
560                         cb, app_key);\r
561                 if(er.encoded == -1) {\r
562                         er.failed_type = td;\r
563                         er.structure_ptr = sptr;\r
564                         return er;\r
565                 }\r
566         } else {\r
567                 /* Disallow: [<tag>] IMPLICIT ANY */\r
568                 assert(type_variant != ASN_OSUBV_ANY || tag_mode != -1);\r
569                 er.encoded = 0;\r
570         }\r
571 \r
572         if(!cb) {\r
573                 er.encoded += (type_variant == ASN_OSUBV_BIT) + st->size;\r
574                 ASN__ENCODED_OK(er);\r
575         }\r
576 \r
577         /*\r
578          * Prepare to deal with the last octet of BIT STRING.\r
579          */\r
580         if(type_variant == ASN_OSUBV_BIT) {\r
581                 uint8_t b = st->bits_unused & 0x07;\r
582                 if(b && st->size) fix_last_byte = 1;\r
583                 ASN__CALLBACK(&b, 1);\r
584         }\r
585 \r
586         /* Invoke callback for the main part of the buffer */\r
587         ASN__CALLBACK(st->buf, st->size - fix_last_byte);\r
588 \r
589         /* The last octet should be stripped off the unused bits */\r
590         if(fix_last_byte) {\r
591                 uint8_t b = st->buf[st->size-1] & (0xff << st->bits_unused);\r
592                 ASN__CALLBACK(&b, 1);\r
593         }\r
594 \r
595         ASN__ENCODED_OK(er);\r
596 cb_failed:\r
597         ASN__ENCODE_FAILED;\r
598 }\r
599 \r
600 asn_enc_rval_t\r
601 OCTET_STRING_encode_xer(const asn_TYPE_descriptor_t *td, const void *sptr,\r
602                         int ilevel, enum xer_encoder_flags_e flags,\r
603                         asn_app_consume_bytes_f *cb, void *app_key) {\r
604     const char * const h2c = "0123456789ABCDEF";\r
605         const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr;\r
606         asn_enc_rval_t er = { 0, 0, 0 };\r
607         char scratch[16 * 3 + 4];\r
608         char *p = scratch;\r
609         uint8_t *buf;\r
610         uint8_t *end;\r
611         size_t i;\r
612 \r
613         if(!st || (!st->buf && st->size))\r
614                 ASN__ENCODE_FAILED;\r
615 \r
616         er.encoded = 0;\r
617 \r
618         /*\r
619          * Dump the contents of the buffer in hexadecimal.\r
620          */\r
621         buf = st->buf;\r
622         end = buf + st->size;\r
623         if(flags & XER_F_CANONICAL) {\r
624                 char *scend = scratch + (sizeof(scratch) - 2);\r
625                 for(; buf < end; buf++) {\r
626                         if(p >= scend) {\r
627                                 ASN__CALLBACK(scratch, p - scratch);\r
628                                 p = scratch;\r
629                         }\r
630                         *p++ = h2c[(*buf >> 4) & 0x0F];\r
631                         *p++ = h2c[*buf & 0x0F];\r
632                 }\r
633 \r
634                 ASN__CALLBACK(scratch, p-scratch);      /* Dump the rest */\r
635         } else {\r
636                 for(i = 0; buf < end; buf++, i++) {\r
637                         if(!(i % 16) && (i || st->size > 16)) {\r
638                                 ASN__CALLBACK(scratch, p-scratch);\r
639                                 p = scratch;\r
640                                 ASN__TEXT_INDENT(1, ilevel);\r
641                         }\r
642                         *p++ = h2c[(*buf >> 4) & 0x0F];\r
643                         *p++ = h2c[*buf & 0x0F];\r
644                         *p++ = 0x20;\r
645                 }\r
646                 if(p - scratch) {\r
647                         p--;    /* Remove the tail space */\r
648                         ASN__CALLBACK(scratch, p-scratch); /* Dump the rest */\r
649                         if(st->size > 16)\r
650                                 ASN__TEXT_INDENT(1, ilevel-1);\r
651                 }\r
652         }\r
653 \r
654         ASN__ENCODED_OK(er);\r
655 cb_failed:\r
656         ASN__ENCODE_FAILED;\r
657 }\r
658 \r
659 static const struct OCTET_STRING__xer_escape_table_s {\r
660         const char *string;\r
661         int size;\r
662 } OCTET_STRING__xer_escape_table[] = {\r
663 #define OSXET(s)        { s, sizeof(s) - 1 }\r
664         OSXET("\074\156\165\154\057\076"),      /* <nul/> */\r
665         OSXET("\074\163\157\150\057\076"),      /* <soh/> */\r
666         OSXET("\074\163\164\170\057\076"),      /* <stx/> */\r
667         OSXET("\074\145\164\170\057\076"),      /* <etx/> */\r
668         OSXET("\074\145\157\164\057\076"),      /* <eot/> */\r
669         OSXET("\074\145\156\161\057\076"),      /* <enq/> */\r
670         OSXET("\074\141\143\153\057\076"),      /* <ack/> */\r
671         OSXET("\074\142\145\154\057\076"),      /* <bel/> */\r
672         OSXET("\074\142\163\057\076"),          /* <bs/> */\r
673         OSXET("\011"),                          /* \t */\r
674         OSXET("\012"),                          /* \n */\r
675         OSXET("\074\166\164\057\076"),          /* <vt/> */\r
676         OSXET("\074\146\146\057\076"),          /* <ff/> */\r
677         OSXET("\015"),                          /* \r */\r
678         OSXET("\074\163\157\057\076"),          /* <so/> */\r
679         OSXET("\074\163\151\057\076"),          /* <si/> */\r
680         OSXET("\074\144\154\145\057\076"),      /* <dle/> */\r
681         OSXET("\074\144\143\061\057\076"),      /* <de1/> */\r
682         OSXET("\074\144\143\062\057\076"),      /* <de2/> */\r
683         OSXET("\074\144\143\063\057\076"),      /* <de3/> */\r
684         OSXET("\074\144\143\064\057\076"),      /* <de4/> */\r
685         OSXET("\074\156\141\153\057\076"),      /* <nak/> */\r
686         OSXET("\074\163\171\156\057\076"),      /* <syn/> */\r
687         OSXET("\074\145\164\142\057\076"),      /* <etb/> */\r
688         OSXET("\074\143\141\156\057\076"),      /* <can/> */\r
689         OSXET("\074\145\155\057\076"),          /* <em/> */\r
690         OSXET("\074\163\165\142\057\076"),      /* <sub/> */\r
691         OSXET("\074\145\163\143\057\076"),      /* <esc/> */\r
692         OSXET("\074\151\163\064\057\076"),      /* <is4/> */\r
693         OSXET("\074\151\163\063\057\076"),      /* <is3/> */\r
694         OSXET("\074\151\163\062\057\076"),      /* <is2/> */\r
695         OSXET("\074\151\163\061\057\076"),      /* <is1/> */\r
696         { 0, 0 },       /* " " */\r
697         { 0, 0 },       /* ! */\r
698         { 0, 0 },       /* \" */\r
699         { 0, 0 },       /* # */\r
700         { 0, 0 },       /* $ */\r
701         { 0, 0 },       /* % */\r
702         OSXET("\046\141\155\160\073"),  /* &amp; */\r
703         { 0, 0 },       /* ' */\r
704         {0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, /* ()*+,-./ */\r
705         {0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, /* 01234567 */\r
706         {0,0},{0,0},{0,0},{0,0},                         /* 89:; */\r
707         OSXET("\046\154\164\073"),      /* &lt; */\r
708         { 0, 0 },       /* = */\r
709         OSXET("\046\147\164\073"),      /* &gt; */\r
710 };\r
711 \r
712 static int\r
713 OS__check_escaped_control_char(const void *buf, int size) {\r
714         size_t i;\r
715         /*\r
716          * Inefficient algorithm which translates the escape sequences\r
717          * defined above into characters. Returns -1 if not found.\r
718          * TODO: replace by a faster algorithm (bsearch(), hash or\r
719          * nested table lookups).\r
720          */\r
721         for(i = 0; i < 32 /* Don't spend time on the bottom half */; i++) {\r
722                 const struct OCTET_STRING__xer_escape_table_s *el;\r
723                 el = &OCTET_STRING__xer_escape_table[i];\r
724                 if(el->size == size && memcmp(buf, el->string, size) == 0)\r
725                         return i;\r
726         }\r
727         return -1;\r
728 }\r
729 \r
730 static int\r
731 OCTET_STRING__handle_control_chars(void *struct_ptr, const void *chunk_buf, size_t chunk_size) {\r
732         /*\r
733          * This might be one of the escape sequences\r
734          * for control characters. Check it out.\r
735          * #11.15.5\r
736          */\r
737         int control_char = OS__check_escaped_control_char(chunk_buf,chunk_size);\r
738         if(control_char >= 0) {\r
739                 OCTET_STRING_t *st = (OCTET_STRING_t *)struct_ptr;\r
740                 void *p = REALLOC(st->buf, st->size + 2);\r
741                 if(p) {\r
742                         st->buf = (uint8_t *)p;\r
743                         st->buf[st->size++] = control_char;\r
744                         st->buf[st->size] = '\0';       /* nul-termination */\r
745                         return 0;\r
746                 }\r
747         }\r
748         \r
749         return -1;      /* No, it's not */\r
750 }\r
751 \r
752 asn_enc_rval_t\r
753 OCTET_STRING_encode_xer_utf8(const asn_TYPE_descriptor_t *td, const void *sptr,\r
754                              int ilevel, enum xer_encoder_flags_e flags,\r
755                              asn_app_consume_bytes_f *cb, void *app_key) {\r
756         const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr;\r
757         asn_enc_rval_t er = { 0, 0, 0 };\r
758         uint8_t *buf, *end;\r
759         uint8_t *ss;    /* Sequence start */\r
760         ssize_t encoded_len = 0;\r
761 \r
762         (void)ilevel;   /* Unused argument */\r
763         (void)flags;    /* Unused argument */\r
764 \r
765         if(!st || (!st->buf && st->size))\r
766                 ASN__ENCODE_FAILED;\r
767 \r
768         buf = st->buf;\r
769         end = buf + st->size;\r
770         for(ss = buf; buf < end; buf++) {\r
771                 unsigned int ch = *buf;\r
772                 int s_len;      /* Special encoding sequence length */\r
773 \r
774                 /*\r
775                  * Escape certain characters: X.680/11.15\r
776                  */\r
777                 if(ch < sizeof(OCTET_STRING__xer_escape_table)\r
778                         /sizeof(OCTET_STRING__xer_escape_table[0])\r
779                 && (s_len = OCTET_STRING__xer_escape_table[ch].size)) {\r
780                         if(((buf - ss) && cb(ss, buf - ss, app_key) < 0)\r
781                         || cb(OCTET_STRING__xer_escape_table[ch].string, s_len,\r
782                                         app_key) < 0)\r
783                                 ASN__ENCODE_FAILED;\r
784                         encoded_len += (buf - ss) + s_len;\r
785                         ss = buf + 1;\r
786                 }\r
787         }\r
788 \r
789         encoded_len += (buf - ss);\r
790         if((buf - ss) && cb(ss, buf - ss, app_key) < 0)\r
791                 ASN__ENCODE_FAILED;\r
792 \r
793         er.encoded = encoded_len;\r
794         ASN__ENCODED_OK(er);\r
795 }\r
796 \r
797 /*\r
798  * Convert from hexadecimal format (cstring): "AB CD EF"\r
799  */\r
800 static ssize_t OCTET_STRING__convert_hexadecimal(void *sptr, const void *chunk_buf, size_t chunk_size, int have_more) {\r
801         OCTET_STRING_t *st = (OCTET_STRING_t *)sptr;\r
802         const char *chunk_stop = (const char *)chunk_buf;\r
803         const char *p = chunk_stop;\r
804         const char *pend = p + chunk_size;\r
805         unsigned int clv = 0;\r
806         int half = 0;   /* Half bit */\r
807         uint8_t *buf;\r
808 \r
809         /* Reallocate buffer according to high cap estimation */\r
810         size_t new_size = st->size + (chunk_size + 1) / 2;\r
811         void *nptr = REALLOC(st->buf, new_size + 1);\r
812         if(!nptr) return -1;\r
813         st->buf = (uint8_t *)nptr;\r
814         buf = st->buf + st->size;\r
815 \r
816         /*\r
817          * If something like " a b c " appears here, the " a b":3 will be\r
818          * converted, and the rest skipped. That is, unless buf_size is greater\r
819          * than chunk_size, then it'll be equivalent to "ABC0".\r
820          */\r
821         for(; p < pend; p++) {\r
822                 int ch = *(const unsigned char *)p;\r
823                 switch(ch) {\r
824                 case 0x09: case 0x0a: case 0x0c: case 0x0d:\r
825                 case 0x20:\r
826                         /* Ignore whitespace */\r
827                         continue;\r
828                 case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: /*01234*/\r
829                 case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: /*56789*/\r
830                         clv = (clv << 4) + (ch - 0x30);\r
831                         break;\r
832                 case 0x41: case 0x42: case 0x43:        /* ABC */\r
833                 case 0x44: case 0x45: case 0x46:        /* DEF */\r
834                         clv = (clv << 4) + (ch - 0x41 + 10);\r
835                         break;\r
836                 case 0x61: case 0x62: case 0x63:        /* abc */\r
837                 case 0x64: case 0x65: case 0x66:        /* def */\r
838                         clv = (clv << 4) + (ch - 0x61 + 10);\r
839                         break;\r
840                 default:\r
841                         *buf = 0;       /* JIC */\r
842                         return -1;\r
843                 }\r
844                 if(half++) {\r
845                         half = 0;\r
846                         *buf++ = clv;\r
847                         chunk_stop = p + 1;\r
848                 }\r
849         }\r
850 \r
851         /*\r
852          * Check partial decoding.\r
853          */\r
854         if(half) {\r
855                 if(have_more) {\r
856                         /*\r
857                          * Partial specification is fine,\r
858                          * because no more more PXER_TEXT data is available.\r
859                          */\r
860                         *buf++ = clv << 4;\r
861                         chunk_stop = p;\r
862                 }\r
863         } else {\r
864                 chunk_stop = p;\r
865         }\r
866 \r
867         st->size = buf - st->buf;       /* Adjust the buffer size */\r
868         assert(st->size <= new_size);\r
869         st->buf[st->size] = 0;          /* Courtesy termination */\r
870 \r
871         return (chunk_stop - (const char *)chunk_buf);  /* Converted size */\r
872 }\r
873 \r
874 /*\r
875  * Convert from binary format: "00101011101"\r
876  */\r
877 static ssize_t OCTET_STRING__convert_binary(void *sptr, const void *chunk_buf, size_t chunk_size, int have_more) {\r
878         BIT_STRING_t *st = (BIT_STRING_t *)sptr;\r
879         const char *p = (const char *)chunk_buf;\r
880         const char *pend = p + chunk_size;\r
881         int bits_unused = st->bits_unused & 0x7;\r
882         uint8_t *buf;\r
883 \r
884         /* Reallocate buffer according to high cap estimation */\r
885         size_t new_size = st->size + (chunk_size + 7) / 8;\r
886         void *nptr = REALLOC(st->buf, new_size + 1);\r
887         if(!nptr) return -1;\r
888         st->buf = (uint8_t *)nptr;\r
889         buf = st->buf + st->size;\r
890 \r
891         (void)have_more;\r
892 \r
893         if(bits_unused == 0)\r
894                 bits_unused = 8;\r
895         else if(st->size)\r
896                 buf--;\r
897 \r
898         /*\r
899          * Convert series of 0 and 1 into the octet string.\r
900          */\r
901         for(; p < pend; p++) {\r
902                 int ch = *(const unsigned char *)p;\r
903                 switch(ch) {\r
904                 case 0x09: case 0x0a: case 0x0c: case 0x0d:\r
905                 case 0x20:\r
906                         /* Ignore whitespace */\r
907                         break;\r
908                 case 0x30:\r
909                 case 0x31:\r
910                         if(bits_unused-- <= 0) {\r
911                                 *++buf = 0;     /* Clean the cell */\r
912                                 bits_unused = 7;\r
913                         }\r
914                         *buf |= (ch&1) << bits_unused;\r
915                         break;\r
916                 default:\r
917                         st->bits_unused = bits_unused;\r
918                         return -1;\r
919                 }\r
920         }\r
921 \r
922         if(bits_unused == 8) {\r
923                 st->size = buf - st->buf;\r
924                 st->bits_unused = 0;\r
925         } else {\r
926                 st->size = buf - st->buf + 1;\r
927                 st->bits_unused = bits_unused;\r
928         }\r
929 \r
930         assert(st->size <= new_size);\r
931         st->buf[st->size] = 0;          /* Courtesy termination */\r
932 \r
933         return chunk_size;      /* Converted in full */\r
934 }\r
935 \r
936 /*\r
937  * Something like strtod(), but with stricter rules.\r
938  */\r
939 static int\r
940 OS__strtoent(int base, const char *buf, const char *end, int32_t *ret_value) {\r
941         const int32_t last_unicode_codepoint = 0x10ffff;\r
942         int32_t val = 0;\r
943         const char *p;\r
944 \r
945         for(p = buf; p < end; p++) {\r
946                 int ch = *p;\r
947 \r
948                 switch(ch) {\r
949                 case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: /*01234*/\r
950                 case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: /*56789*/\r
951                         val = val * base + (ch - 0x30);\r
952                         break;\r
953                 case 0x41: case 0x42: case 0x43:        /* ABC */\r
954                 case 0x44: case 0x45: case 0x46:        /* DEF */\r
955                         val = val * base + (ch - 0x41 + 10);\r
956                         break;\r
957                 case 0x61: case 0x62: case 0x63:        /* abc */\r
958                 case 0x64: case 0x65: case 0x66:        /* def */\r
959                         val = val * base + (ch - 0x61 + 10);\r
960                         break;\r
961                 case 0x3b:      /* ';' */\r
962                         *ret_value = val;\r
963                         return (p - buf) + 1;\r
964                 default:\r
965                         return -1;      /* Character set error */\r
966                 }\r
967 \r
968                 /* Value exceeds the Unicode range. */\r
969                 if(val > last_unicode_codepoint) {\r
970                         return -1;\r
971                 }\r
972         }\r
973 \r
974         *ret_value = -1;\r
975         return (p - buf);\r
976 }\r
977 \r
978 /*\r
979  * Convert from the plain UTF-8 format, expanding entity references: "2 &lt; 3"\r
980  */\r
981 static ssize_t\r
982 OCTET_STRING__convert_entrefs(void *sptr, const void *chunk_buf,\r
983                               size_t chunk_size, int have_more) {\r
984     OCTET_STRING_t *st = (OCTET_STRING_t *)sptr;\r
985         const char *p = (const char *)chunk_buf;\r
986         const char *pend = p + chunk_size;\r
987         uint8_t *buf;\r
988 \r
989         /* Reallocate buffer */\r
990         size_t new_size = st->size + chunk_size;\r
991         void *nptr = REALLOC(st->buf, new_size + 1);\r
992         if(!nptr) return -1;\r
993         st->buf = (uint8_t *)nptr;\r
994         buf = st->buf + st->size;\r
995 \r
996         /*\r
997          * Convert series of 0 and 1 into the octet string.\r
998          */\r
999         for(; p < pend; p++) {\r
1000                 int ch = *(const unsigned char *)p;\r
1001                 int len;        /* Length of the rest of the chunk */\r
1002 \r
1003                 if(ch != 0x26 /* '&' */) {\r
1004                         *buf++ = ch;\r
1005                         continue;       /* That was easy... */\r
1006                 }\r
1007 \r
1008                 /*\r
1009                  * Process entity reference.\r
1010                  */\r
1011                 len = chunk_size - (p - (const char *)chunk_buf);\r
1012                 if(len == 1 /* "&" */) goto want_more;\r
1013                 if(p[1] == 0x23 /* '#' */) {\r
1014                         const char *pval;       /* Pointer to start of digits */\r
1015                         int32_t val = 0;        /* Entity reference value */\r
1016                         int base;\r
1017 \r
1018                         if(len == 2 /* "&#" */) goto want_more;\r
1019                         if(p[2] == 0x78 /* 'x' */)\r
1020                                 pval = p + 3, base = 16;\r
1021                         else\r
1022                                 pval = p + 2, base = 10;\r
1023                         len = OS__strtoent(base, pval, p + len, &val);\r
1024                         if(len == -1) {\r
1025                                 /* Invalid charset. Just copy verbatim. */\r
1026                                 *buf++ = ch;\r
1027                                 continue;\r
1028                         }\r
1029                         if(!len || pval[len-1] != 0x3b) goto want_more;\r
1030                         assert(val > 0);\r
1031                         p += (pval - p) + len - 1; /* Advance past entref */\r
1032 \r
1033                         if(val < 0x80) {\r
1034                                 *buf++ = (char)val;\r
1035                         } else if(val < 0x800) {\r
1036                                 *buf++ = 0xc0 | ((val >> 6));\r
1037                                 *buf++ = 0x80 | ((val & 0x3f));\r
1038                         } else if(val < 0x10000) {\r
1039                                 *buf++ = 0xe0 | ((val >> 12));\r
1040                                 *buf++ = 0x80 | ((val >> 6) & 0x3f);\r
1041                                 *buf++ = 0x80 | ((val & 0x3f));\r
1042                         } else if(val < 0x200000) {\r
1043                                 *buf++ = 0xf0 | ((val >> 18));\r
1044                                 *buf++ = 0x80 | ((val >> 12) & 0x3f);\r
1045                                 *buf++ = 0x80 | ((val >> 6) & 0x3f);\r
1046                                 *buf++ = 0x80 | ((val & 0x3f));\r
1047                         } else if(val < 0x4000000) {\r
1048                                 *buf++ = 0xf8 | ((val >> 24));\r
1049                                 *buf++ = 0x80 | ((val >> 18) & 0x3f);\r
1050                                 *buf++ = 0x80 | ((val >> 12) & 0x3f);\r
1051                                 *buf++ = 0x80 | ((val >> 6) & 0x3f);\r
1052                                 *buf++ = 0x80 | ((val & 0x3f));\r
1053                         } else {\r
1054                                 *buf++ = 0xfc | ((val >> 30) & 0x1);\r
1055                                 *buf++ = 0x80 | ((val >> 24) & 0x3f);\r
1056                                 *buf++ = 0x80 | ((val >> 18) & 0x3f);\r
1057                                 *buf++ = 0x80 | ((val >> 12) & 0x3f);\r
1058                                 *buf++ = 0x80 | ((val >> 6) & 0x3f);\r
1059                                 *buf++ = 0x80 | ((val & 0x3f));\r
1060                         }\r
1061                 } else {\r
1062                         /*\r
1063                          * Ugly, limited parsing of &amp; &gt; &lt;\r
1064                          */\r
1065                         char *sc = (char *)memchr(p, 0x3b, len > 5 ? 5 : len);\r
1066                         if(!sc) goto want_more;\r
1067                         if((sc - p) == 4\r
1068                                 && p[1] == 0x61 /* 'a' */\r
1069                                 && p[2] == 0x6d /* 'm' */\r
1070                                 && p[3] == 0x70 /* 'p' */) {\r
1071                                 *buf++ = 0x26;\r
1072                                 p = sc;\r
1073                                 continue;\r
1074                         }\r
1075                         if((sc - p) == 3) {\r
1076                                 if(p[1] == 0x6c) {\r
1077                                         *buf = 0x3c;    /* '<' */\r
1078                                 } else if(p[1] == 0x67) {\r
1079                                         *buf = 0x3e;    /* '>' */\r
1080                                 } else {\r
1081                                         /* Unsupported entity reference */\r
1082                                         *buf++ = ch;\r
1083                                         continue;\r
1084                                 }\r
1085                                 if(p[2] != 0x74) {\r
1086                                         /* Unsupported entity reference */\r
1087                                         *buf++ = ch;\r
1088                                         continue;\r
1089                                 }\r
1090                                 buf++;\r
1091                                 p = sc;\r
1092                                 continue;\r
1093                         }\r
1094                         /* Unsupported entity reference */\r
1095                         *buf++ = ch;\r
1096                 }\r
1097 \r
1098                 continue;\r
1099         want_more:\r
1100                 if(have_more) {\r
1101                         /*\r
1102                          * We know that no more data (of the same type)\r
1103                          * is coming. Copy the rest verbatim.\r
1104                          */\r
1105                         *buf++ = ch;\r
1106                         continue;\r
1107                 }\r
1108                 chunk_size = (p - (const char *)chunk_buf);\r
1109                 /* Processing stalled: need more data */\r
1110                 break;\r
1111         }\r
1112 \r
1113         st->size = buf - st->buf;\r
1114         assert(st->size <= new_size);\r
1115         st->buf[st->size] = 0;          /* Courtesy termination */\r
1116 \r
1117         return chunk_size;      /* Converted in full */\r
1118 }\r
1119 \r
1120 /*\r
1121  * Decode OCTET STRING from the XML element's body.\r
1122  */\r
1123 static asn_dec_rval_t\r
1124 OCTET_STRING__decode_xer(\r
1125     const asn_codec_ctx_t *opt_codec_ctx, const asn_TYPE_descriptor_t *td,\r
1126     void **sptr, const char *opt_mname, const void *buf_ptr, size_t size,\r
1127     int (*opt_unexpected_tag_decoder)(void *struct_ptr, const void *chunk_buf,\r
1128                                       size_t chunk_size),\r
1129     ssize_t (*body_receiver)(void *struct_ptr, const void *chunk_buf,\r
1130                              size_t chunk_size, int have_more)) {\r
1131     OCTET_STRING_t *st = (OCTET_STRING_t *)*sptr;\r
1132         const asn_OCTET_STRING_specifics_t *specs = td->specifics\r
1133                                 ? (const asn_OCTET_STRING_specifics_t *)td->specifics\r
1134                                 : &asn_SPC_OCTET_STRING_specs;\r
1135         const char *xml_tag = opt_mname ? opt_mname : td->xml_tag;\r
1136         asn_struct_ctx_t *ctx;          /* Per-structure parser context */\r
1137         asn_dec_rval_t rval;            /* Return value from the decoder */\r
1138         int st_allocated;\r
1139 \r
1140         /*\r
1141          * Create the string if does not exist.\r
1142          */\r
1143         if(!st) {\r
1144                 st = (OCTET_STRING_t *)CALLOC(1, specs->struct_size);\r
1145                 *sptr = (void *)st;\r
1146                 if(!st) goto sta_failed;\r
1147                 st_allocated = 1;\r
1148         } else {\r
1149                 st_allocated = 0;\r
1150         }\r
1151         if(!st->buf) {\r
1152                 /* This is separate from above section */\r
1153                 st->buf = (uint8_t *)CALLOC(1, 1);\r
1154                 if(!st->buf) {\r
1155                         if(st_allocated) {\r
1156                                 *sptr = 0;\r
1157                                 goto stb_failed;\r
1158                         } else {\r
1159                                 goto sta_failed;\r
1160                         }\r
1161                 }\r
1162         }\r
1163 \r
1164         /* Restore parsing context */\r
1165         ctx = (asn_struct_ctx_t *)(((char *)*sptr) + specs->ctx_offset);\r
1166 \r
1167         return xer_decode_general(opt_codec_ctx, ctx, *sptr, xml_tag,\r
1168                 buf_ptr, size, opt_unexpected_tag_decoder, body_receiver);\r
1169 \r
1170 stb_failed:\r
1171         FREEMEM(st);\r
1172 sta_failed:\r
1173         rval.code = RC_FAIL;\r
1174         rval.consumed = 0;\r
1175         return rval;\r
1176 }\r
1177 \r
1178 /*\r
1179  * Decode OCTET STRING from the hexadecimal data.\r
1180  */\r
1181 asn_dec_rval_t\r
1182 OCTET_STRING_decode_xer_hex(const asn_codec_ctx_t *opt_codec_ctx,\r
1183                             const asn_TYPE_descriptor_t *td, void **sptr,\r
1184                             const char *opt_mname, const void *buf_ptr,\r
1185                             size_t size) {\r
1186     return OCTET_STRING__decode_xer(opt_codec_ctx, td, sptr, opt_mname,\r
1187                 buf_ptr, size, 0, OCTET_STRING__convert_hexadecimal);\r
1188 }\r
1189 \r
1190 /*\r
1191  * Decode OCTET STRING from the binary (0/1) data.\r
1192  */\r
1193 asn_dec_rval_t\r
1194 OCTET_STRING_decode_xer_binary(const asn_codec_ctx_t *opt_codec_ctx,\r
1195                                const asn_TYPE_descriptor_t *td, void **sptr,\r
1196                                const char *opt_mname, const void *buf_ptr,\r
1197                                size_t size) {\r
1198     return OCTET_STRING__decode_xer(opt_codec_ctx, td, sptr, opt_mname,\r
1199                 buf_ptr, size, 0, OCTET_STRING__convert_binary);\r
1200 }\r
1201 \r
1202 /*\r
1203  * Decode OCTET STRING from the string (ASCII/UTF-8) data.\r
1204  */\r
1205 asn_dec_rval_t\r
1206 OCTET_STRING_decode_xer_utf8(const asn_codec_ctx_t *opt_codec_ctx,\r
1207                              const asn_TYPE_descriptor_t *td, void **sptr,\r
1208                              const char *opt_mname, const void *buf_ptr,\r
1209                              size_t size) {\r
1210     return OCTET_STRING__decode_xer(opt_codec_ctx, td, sptr, opt_mname,\r
1211                 buf_ptr, size,\r
1212                 OCTET_STRING__handle_control_chars,\r
1213                 OCTET_STRING__convert_entrefs);\r
1214 }\r
1215 \r
1216 #ifndef  ASN_DISABLE_PER_SUPPORT\r
1217 \r
1218 static int\r
1219 OCTET_STRING_per_get_characters(asn_per_data_t *po, uint8_t *buf,\r
1220                 size_t units, unsigned int bpc, unsigned int unit_bits,\r
1221                 long lb, long ub, const asn_per_constraints_t *pc) {\r
1222         uint8_t *end = buf + units * bpc;\r
1223 \r
1224         ASN_DEBUG("Expanding %d characters into (%ld..%ld):%d",\r
1225                 (int)units, lb, ub, unit_bits);\r
1226 \r
1227         /* X.691: 27.5.4 */\r
1228         if((unsigned long)ub <= ((unsigned long)2 << (unit_bits - 1))) {\r
1229                 /* Decode without translation */\r
1230                 lb = 0;\r
1231         } else if(pc && pc->code2value) {\r
1232                 if(unit_bits > 16)\r
1233                         return 1;       /* FATAL: can't have constrained\r
1234                                          * UniversalString with more than\r
1235                                          * 16 million code points */\r
1236                 for(; buf < end; buf += bpc) {\r
1237                         int value;\r
1238                         int code = per_get_few_bits(po, unit_bits);\r
1239                         if(code < 0) return -1; /* WMORE */\r
1240                         value = pc->code2value(code);\r
1241                         if(value < 0) {\r
1242                                 ASN_DEBUG("Code %d (0x%02x) is"\r
1243                                         " not in map (%ld..%ld)",\r
1244                                         code, code, lb, ub);\r
1245                                 return 1;       /* FATAL */\r
1246                         }\r
1247                         switch(bpc) {\r
1248                         case 1: *buf = value; break;\r
1249                         case 2: buf[0] = value >> 8; buf[1] = value; break;\r
1250                         case 4: buf[0] = value >> 24; buf[1] = value >> 16;\r
1251                                 buf[2] = value >> 8; buf[3] = value; break;\r
1252                         }\r
1253                 }\r
1254                 return 0;\r
1255         }\r
1256 \r
1257         /* Shortcut the no-op copying to the aligned structure */\r
1258         if(lb == 0 && (unit_bits == 8 * bpc)) {\r
1259                 return per_get_many_bits(po, buf, 0, unit_bits * units);\r
1260         }\r
1261 \r
1262         for(; buf < end; buf += bpc) {\r
1263                 int32_t code = per_get_few_bits(po, unit_bits);\r
1264                 int32_t ch = code + lb;\r
1265                 if(code < 0) return -1; /* WMORE */\r
1266                 if(ch > ub) {\r
1267                         ASN_DEBUG("Code %d is out of range (%ld..%ld)",\r
1268                                 ch, lb, ub);\r
1269                         return 1;       /* FATAL */\r
1270                 }\r
1271                 switch(bpc) {\r
1272                 case 1: *buf = ch; break;\r
1273                 case 2: buf[0] = ch >> 8; buf[1] = ch; break;\r
1274                 case 4: buf[0] = ch >> 24; buf[1] = ch >> 16;\r
1275                         buf[2] = ch >> 8; buf[3] = ch; break;\r
1276                 }\r
1277         }\r
1278 \r
1279         return 0;\r
1280 }\r
1281 \r
1282 static int\r
1283 OCTET_STRING_per_put_characters(asn_per_outp_t *po, const uint8_t *buf,\r
1284                 size_t units, unsigned int bpc, unsigned int unit_bits,\r
1285                 long lb, long ub, const asn_per_constraints_t *pc) {\r
1286         const uint8_t *end = buf + units * bpc;\r
1287 \r
1288         ASN_DEBUG("Squeezing %d characters into (%ld..%ld):%d (%d bpc)",\r
1289                 (int)units, lb, ub, unit_bits, bpc);\r
1290 \r
1291         /* X.691: 27.5.4 */\r
1292         if((unsigned long)ub <= ((unsigned long)2 << (unit_bits - 1))) {\r
1293                 /* Encode as is */\r
1294                 lb = 0;\r
1295         } else if(pc && pc->value2code) {\r
1296                 for(; buf < end; buf += bpc) {\r
1297                         int code;\r
1298                         uint32_t value;\r
1299                         switch(bpc) {\r
1300                         case 1: value = *(const uint8_t *)buf; break;\r
1301                         case 2: value = (buf[0] << 8) | buf[1]; break;\r
1302                         case 4: value = (buf[0] << 24) | (buf[1] << 16)\r
1303                                         | (buf[2] << 8) | buf[3]; break;\r
1304                         default: return -1;\r
1305                         }\r
1306                         code = pc->value2code(value);\r
1307                         if(code < 0) {\r
1308                                 ASN_DEBUG("Character %d (0x%02x) is"\r
1309                                         " not in map (%ld..%ld)",\r
1310                                         *buf, *buf, lb, ub);\r
1311                                 return -1;\r
1312                         }\r
1313                         if(per_put_few_bits(po, code, unit_bits))\r
1314                                 return -1;\r
1315                 }\r
1316         }\r
1317 \r
1318         /* Shortcut the no-op copying to the aligned structure */\r
1319         if(lb == 0 && (unit_bits == 8 * bpc)) {\r
1320                 return per_put_many_bits(po, buf, unit_bits * units);\r
1321         }\r
1322 \r
1323     for(ub -= lb; buf < end; buf += bpc) {\r
1324         int ch;\r
1325         uint32_t value;\r
1326         switch(bpc) {\r
1327         case 1:\r
1328             value = *(const uint8_t *)buf;\r
1329             break;\r
1330         case 2:\r
1331             value = (buf[0] << 8) | buf[1];\r
1332             break;\r
1333         case 4:\r
1334             value = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];\r
1335             break;\r
1336         default:\r
1337             return -1;\r
1338         }\r
1339         ch = value - lb;\r
1340         if(ch < 0 || ch > ub) {\r
1341             ASN_DEBUG("Character %d (0x%02x) is out of range (%ld..%ld)", *buf,\r
1342                       value, lb, ub + lb);\r
1343             return -1;\r
1344         }\r
1345         if(per_put_few_bits(po, ch, unit_bits)) return -1;\r
1346     }\r
1347 \r
1348     return 0;\r
1349 }\r
1350 \r
1351 static asn_per_constraints_t asn_DEF_OCTET_STRING_constraints = {\r
1352         { APC_CONSTRAINED, 8, 8, 0, 255 },\r
1353         { APC_SEMI_CONSTRAINED, -1, -1, 0, 0 },\r
1354         0, 0\r
1355 };\r
1356 \r
1357 asn_dec_rval_t\r
1358 OCTET_STRING_decode_uper(const asn_codec_ctx_t *opt_codec_ctx,\r
1359                          const asn_TYPE_descriptor_t *td,\r
1360                          const asn_per_constraints_t *constraints, void **sptr,\r
1361                          asn_per_data_t *pd) {\r
1362     const asn_OCTET_STRING_specifics_t *specs = td->specifics\r
1363                 ? (const asn_OCTET_STRING_specifics_t *)td->specifics\r
1364                 : &asn_SPC_OCTET_STRING_specs;\r
1365     const asn_per_constraints_t *pc =\r
1366         constraints ? constraints : td->encoding_constraints.per_constraints;\r
1367     const asn_per_constraint_t *cval;\r
1368         const asn_per_constraint_t *csiz;\r
1369         asn_dec_rval_t rval = { RC_OK, 0 };\r
1370         OCTET_STRING_t *st = (OCTET_STRING_t *)*sptr;\r
1371         ssize_t consumed_myself = 0;\r
1372         int repeat;\r
1373         enum {\r
1374                 OS__BPC_CHAR    = 1,\r
1375                 OS__BPC_U16     = 2,\r
1376                 OS__BPC_U32     = 4\r
1377         } bpc;  /* Bytes per character */\r
1378         unsigned int unit_bits;\r
1379         unsigned int canonical_unit_bits;\r
1380 \r
1381         (void)opt_codec_ctx;\r
1382 \r
1383         if(pc) {\r
1384                 cval = &pc->value;\r
1385                 csiz = &pc->size;\r
1386         } else {\r
1387                 cval = &asn_DEF_OCTET_STRING_constraints.value;\r
1388                 csiz = &asn_DEF_OCTET_STRING_constraints.size;\r
1389         }\r
1390 \r
1391         switch(specs->subvariant) {\r
1392         default:\r
1393         case ASN_OSUBV_ANY:\r
1394         case ASN_OSUBV_BIT:\r
1395                 ASN_DEBUG("Unrecognized subvariant %d", specs->subvariant);\r
1396                 RETURN(RC_FAIL);\r
1397                 break;\r
1398         case ASN_OSUBV_STR:\r
1399                 canonical_unit_bits = unit_bits = 8;\r
1400                 if(cval->flags & APC_CONSTRAINED)\r
1401                         unit_bits = cval->range_bits;\r
1402                 bpc = OS__BPC_CHAR;\r
1403                 break;\r
1404         case ASN_OSUBV_U16:\r
1405                 canonical_unit_bits = unit_bits = 16;\r
1406                 if(cval->flags & APC_CONSTRAINED)\r
1407                         unit_bits = cval->range_bits;\r
1408                 bpc = OS__BPC_U16;\r
1409                 break;\r
1410         case ASN_OSUBV_U32:\r
1411                 canonical_unit_bits = unit_bits = 32;\r
1412                 if(cval->flags & APC_CONSTRAINED)\r
1413                         unit_bits = cval->range_bits;\r
1414                 bpc = OS__BPC_U32;\r
1415                 break;\r
1416         }\r
1417 \r
1418         /*\r
1419          * Allocate the string.\r
1420          */\r
1421         if(!st) {\r
1422                 st = (OCTET_STRING_t *)(*sptr = CALLOC(1, specs->struct_size));\r
1423                 if(!st) RETURN(RC_FAIL);\r
1424         }\r
1425 \r
1426         ASN_DEBUG("PER Decoding %s size %ld .. %ld bits %d",\r
1427                 csiz->flags & APC_EXTENSIBLE ? "extensible" : "non-extensible",\r
1428                 csiz->lower_bound, csiz->upper_bound, csiz->effective_bits);\r
1429 \r
1430         if(csiz->flags & APC_EXTENSIBLE) {\r
1431                 int inext = per_get_few_bits(pd, 1);\r
1432                 if(inext < 0) RETURN(RC_WMORE);\r
1433                 if(inext) {\r
1434                         csiz = &asn_DEF_OCTET_STRING_constraints.size;\r
1435                         unit_bits = canonical_unit_bits;\r
1436                 }\r
1437         }\r
1438 \r
1439         if(csiz->effective_bits >= 0) {\r
1440                 FREEMEM(st->buf);\r
1441                 if(bpc) {\r
1442                         st->size = csiz->upper_bound * bpc;\r
1443                 } else {\r
1444                         st->size = (csiz->upper_bound + 7) >> 3;\r
1445                 }\r
1446                 st->buf = (uint8_t *)MALLOC(st->size + 1);\r
1447                 if(!st->buf) { st->size = 0; RETURN(RC_FAIL); }\r
1448         }\r
1449 \r
1450         /* X.691, #16.5: zero-length encoding */\r
1451         /* X.691, #16.6: short fixed length encoding (up to 2 octets) */\r
1452         /* X.691, #16.7: long fixed length encoding (up to 64K octets) */\r
1453         if(csiz->effective_bits == 0) {\r
1454                 int ret;\r
1455                 if(bpc) {\r
1456                         ASN_DEBUG("Encoding OCTET STRING size %ld",\r
1457                                 csiz->upper_bound);\r
1458                         ret = OCTET_STRING_per_get_characters(pd, st->buf,\r
1459                                 csiz->upper_bound, bpc, unit_bits,\r
1460                                 cval->lower_bound, cval->upper_bound, pc);\r
1461                         if(ret > 0) RETURN(RC_FAIL);\r
1462                 } else {\r
1463                         ASN_DEBUG("Encoding BIT STRING size %ld",\r
1464                                 csiz->upper_bound);\r
1465                         ret = per_get_many_bits(pd, st->buf, 0,\r
1466                                             unit_bits * csiz->upper_bound);\r
1467                 }\r
1468                 if(ret < 0) RETURN(RC_WMORE);\r
1469                 consumed_myself += unit_bits * csiz->upper_bound;\r
1470                 st->buf[st->size] = 0;\r
1471                 RETURN(RC_OK);\r
1472         }\r
1473 \r
1474         st->size = 0;\r
1475         do {\r
1476                 ssize_t raw_len;\r
1477                 ssize_t len_bytes;\r
1478                 void *p;\r
1479                 int ret;\r
1480 \r
1481                 /* Get the PER length */\r
1482                 raw_len = uper_get_length(pd, csiz->effective_bits, csiz->lower_bound,\r
1483                                           &repeat);\r
1484                 if(raw_len < 0) RETURN(RC_WMORE);\r
1485                 if(raw_len == 0 && st->buf) break;\r
1486 \r
1487                 ASN_DEBUG("Got PER length eb %ld, len %ld, %s (%s)",\r
1488                         (long)csiz->effective_bits, (long)raw_len,\r
1489                         repeat ? "repeat" : "once", td->name);\r
1490         len_bytes = raw_len * bpc;\r
1491                 p = REALLOC(st->buf, st->size + len_bytes + 1);\r
1492                 if(!p) RETURN(RC_FAIL);\r
1493                 st->buf = (uint8_t *)p;\r
1494 \r
1495         ret = OCTET_STRING_per_get_characters(pd, &st->buf[st->size], raw_len,\r
1496                                               bpc, unit_bits, cval->lower_bound,\r
1497                                               cval->upper_bound, pc);\r
1498         if(ret > 0) RETURN(RC_FAIL);\r
1499                 if(ret < 0) RETURN(RC_WMORE);\r
1500                 st->size += len_bytes;\r
1501         } while(repeat);\r
1502         st->buf[st->size] = 0;  /* nul-terminate */\r
1503 \r
1504         return rval;\r
1505 }\r
1506 \r
1507 asn_enc_rval_t\r
1508 OCTET_STRING_encode_uper(const asn_TYPE_descriptor_t *td,\r
1509                          const asn_per_constraints_t *constraints,\r
1510                          const void *sptr, asn_per_outp_t *po) {\r
1511     const asn_OCTET_STRING_specifics_t *specs = td->specifics\r
1512                 ? (const asn_OCTET_STRING_specifics_t *)td->specifics\r
1513                 : &asn_SPC_OCTET_STRING_specs;\r
1514         const asn_per_constraints_t *pc = constraints ? constraints\r
1515                                 : td->encoding_constraints.per_constraints;\r
1516         const asn_per_constraint_t *cval;\r
1517         const asn_per_constraint_t *csiz;\r
1518         const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr;\r
1519         asn_enc_rval_t er = { 0, 0, 0 };\r
1520         int inext = 0;          /* Lies not within extension root */\r
1521         unsigned int unit_bits;\r
1522         unsigned int canonical_unit_bits;\r
1523         size_t size_in_units;\r
1524         const uint8_t *buf;\r
1525         int ret;\r
1526         enum {\r
1527                 OS__BPC_CHAR    = 1,\r
1528                 OS__BPC_U16     = 2,\r
1529                 OS__BPC_U32     = 4\r
1530         } bpc;  /* Bytes per character */\r
1531         int ct_extensible;\r
1532 \r
1533         if(!st || (!st->buf && st->size))\r
1534                 ASN__ENCODE_FAILED;\r
1535 \r
1536         if(pc) {\r
1537                 cval = &pc->value;\r
1538                 csiz = &pc->size;\r
1539         } else {\r
1540                 cval = &asn_DEF_OCTET_STRING_constraints.value;\r
1541                 csiz = &asn_DEF_OCTET_STRING_constraints.size;\r
1542         }\r
1543         ct_extensible = csiz->flags & APC_EXTENSIBLE;\r
1544 \r
1545         switch(specs->subvariant) {\r
1546         default:\r
1547         case ASN_OSUBV_ANY:\r
1548         case ASN_OSUBV_BIT:\r
1549                 ASN__ENCODE_FAILED;\r
1550         case ASN_OSUBV_STR:\r
1551                 canonical_unit_bits = unit_bits = 8;\r
1552                 if(cval->flags & APC_CONSTRAINED)\r
1553                         unit_bits = cval->range_bits;\r
1554                 bpc = OS__BPC_CHAR;\r
1555                 size_in_units = st->size;\r
1556                 break;\r
1557         case ASN_OSUBV_U16:\r
1558                 canonical_unit_bits = unit_bits = 16;\r
1559                 if(cval->flags & APC_CONSTRAINED)\r
1560                         unit_bits = cval->range_bits;\r
1561                 bpc = OS__BPC_U16;\r
1562                 size_in_units = st->size >> 1;\r
1563                 if(st->size & 1) {\r
1564                         ASN_DEBUG("%s string size is not modulo 2", td->name);\r
1565                         ASN__ENCODE_FAILED;\r
1566                 }\r
1567                 break;\r
1568         case ASN_OSUBV_U32:\r
1569                 canonical_unit_bits = unit_bits = 32;\r
1570                 if(cval->flags & APC_CONSTRAINED)\r
1571                         unit_bits = cval->range_bits;\r
1572                 bpc = OS__BPC_U32;\r
1573                 size_in_units = st->size >> 2;\r
1574                 if(st->size & 3) {\r
1575                         ASN_DEBUG("%s string size is not modulo 4", td->name);\r
1576                         ASN__ENCODE_FAILED;\r
1577                 }\r
1578                 break;\r
1579         }\r
1580 \r
1581         ASN_DEBUG("Encoding %s into %" ASN_PRI_SIZE " units of %d bits"\r
1582                 " (%ld..%ld, effective %d)%s",\r
1583                 td->name, size_in_units, unit_bits,\r
1584                 csiz->lower_bound, csiz->upper_bound,\r
1585                 csiz->effective_bits, ct_extensible ? " EXT" : "");\r
1586 \r
1587         /* Figure out whether size lies within PER visible constraint */\r
1588 \r
1589     if(csiz->effective_bits >= 0) {\r
1590         if((ssize_t)size_in_units < csiz->lower_bound\r
1591            || (ssize_t)size_in_units > csiz->upper_bound) {\r
1592             if(ct_extensible) {\r
1593                 csiz = &asn_DEF_OCTET_STRING_constraints.size;\r
1594                 unit_bits = canonical_unit_bits;\r
1595                 inext = 1;\r
1596             } else {\r
1597                 ASN__ENCODE_FAILED;\r
1598             }\r
1599         }\r
1600     } else {\r
1601         inext = 0;\r
1602     }\r
1603 \r
1604     if(ct_extensible) {\r
1605                 /* Declare whether length is [not] within extension root */\r
1606                 if(per_put_few_bits(po, inext, 1))\r
1607                         ASN__ENCODE_FAILED;\r
1608         }\r
1609 \r
1610     if(csiz->effective_bits >= 0 && !inext) {\r
1611         ASN_DEBUG("Encoding %" ASN_PRI_SIZE " bytes (%ld), length in %d bits", st->size,\r
1612                   size_in_units - csiz->lower_bound, csiz->effective_bits);\r
1613         ret = per_put_few_bits(po, size_in_units - csiz->lower_bound,\r
1614                                csiz->effective_bits);\r
1615         if(ret) ASN__ENCODE_FAILED;\r
1616         ret = OCTET_STRING_per_put_characters(po, st->buf, size_in_units, bpc,\r
1617                                               unit_bits, cval->lower_bound,\r
1618                                               cval->upper_bound, pc);\r
1619         if(ret) ASN__ENCODE_FAILED;\r
1620         ASN__ENCODED_OK(er);\r
1621     }\r
1622 \r
1623     ASN_DEBUG("Encoding %" ASN_PRI_SIZE " bytes", st->size);\r
1624 \r
1625     buf = st->buf;\r
1626     ASN_DEBUG("Encoding %" ASN_PRI_SIZE " in units", size_in_units);\r
1627     do {\r
1628         int need_eom = 0;\r
1629         ssize_t may_save = uper_put_length(po, size_in_units, &need_eom);\r
1630         if(may_save < 0) ASN__ENCODE_FAILED;\r
1631 \r
1632         ASN_DEBUG("Encoding %" ASN_PRI_SSIZE " of %" ASN_PRI_SIZE "%s", may_save, size_in_units,\r
1633                   need_eom ? ",+EOM" : "");\r
1634 \r
1635         ret = OCTET_STRING_per_put_characters(po, buf, may_save, bpc, unit_bits,\r
1636                                               cval->lower_bound,\r
1637                                               cval->upper_bound, pc);\r
1638         if(ret) ASN__ENCODE_FAILED;\r
1639 \r
1640         buf += may_save * bpc;\r
1641         size_in_units -= may_save;\r
1642         assert(!(may_save & 0x07) || !size_in_units);\r
1643         if(need_eom && uper_put_length(po, 0, 0))\r
1644             ASN__ENCODE_FAILED; /* End of Message length */\r
1645     } while(size_in_units);\r
1646 \r
1647     ASN__ENCODED_OK(er);\r
1648 }\r
1649 \r
1650 asn_dec_rval_t\r
1651 OCTET_STRING_decode_aper(const asn_codec_ctx_t *opt_codec_ctx,\r
1652                          const asn_TYPE_descriptor_t *td,\r
1653                          const asn_per_constraints_t *constraints,\r
1654                          void **sptr, asn_per_data_t *pd) {\r
1655 \r
1656         const asn_OCTET_STRING_specifics_t *specs = td->specifics\r
1657                 ? (const asn_OCTET_STRING_specifics_t *)td->specifics\r
1658                 : &asn_SPC_OCTET_STRING_specs;\r
1659         const asn_per_constraints_t *pc = constraints ? constraints\r
1660                                 : td->encoding_constraints.per_constraints;\r
1661         const asn_per_constraint_t *cval;\r
1662         const asn_per_constraint_t *csiz;\r
1663         asn_dec_rval_t rval = { RC_OK, 0 };\r
1664         BIT_STRING_t *st = (BIT_STRING_t *)*sptr;\r
1665         ssize_t consumed_myself = 0;\r
1666         int repeat;\r
1667         enum {\r
1668                 OS__BPC_BIT     = 0,\r
1669                 OS__BPC_CHAR    = 1,\r
1670                 OS__BPC_U16     = 2,\r
1671                 OS__BPC_U32     = 4\r
1672         } bpc;  /* Bytes per character */\r
1673         unsigned int unit_bits;\r
1674         unsigned int canonical_unit_bits;\r
1675 \r
1676         (void)opt_codec_ctx;\r
1677 \r
1678         if(pc) {\r
1679                 cval = &pc->value;\r
1680                 csiz = &pc->size;\r
1681         } else {\r
1682                 cval = &asn_DEF_OCTET_STRING_constraints.value;\r
1683                 csiz = &asn_DEF_OCTET_STRING_constraints.size;\r
1684         }\r
1685 \r
1686         switch(specs->subvariant) {\r
1687         default:\r
1688 /*      case ASN_OSUBV_ANY:\r
1689                 ASN_DEBUG("Unrecognized subvariant %d", specs->subvariant);\r
1690                 RETURN(RC_FAIL);\r
1691 */\r
1692         case ASN_OSUBV_BIT:\r
1693                 canonical_unit_bits = unit_bits = 1;\r
1694                 bpc = OS__BPC_BIT;\r
1695                 break;\r
1696         case ASN_OSUBV_ANY:\r
1697         case ASN_OSUBV_STR:\r
1698                 canonical_unit_bits = unit_bits = 8;\r
1699 /*              if(cval->flags & APC_CONSTRAINED)\r
1700                         unit_bits = cval->range_bits;\r
1701 */\r
1702                 bpc = OS__BPC_CHAR;\r
1703                 break;\r
1704         case ASN_OSUBV_U16:\r
1705                 canonical_unit_bits = unit_bits = 16;\r
1706                 if(cval->flags & APC_CONSTRAINED)\r
1707                         unit_bits = cval->range_bits;\r
1708                 bpc = OS__BPC_U16;\r
1709                 break;\r
1710         case ASN_OSUBV_U32:\r
1711                 canonical_unit_bits = unit_bits = 32;\r
1712                 if(cval->flags & APC_CONSTRAINED)\r
1713                         unit_bits = cval->range_bits;\r
1714                 bpc = OS__BPC_U32;\r
1715                 break;\r
1716         }\r
1717 \r
1718         /*\r
1719          * Allocate the string.\r
1720          */\r
1721         if(!st) {\r
1722                 st = (BIT_STRING_t *)(*sptr = CALLOC(1, specs->struct_size));\r
1723                 if(!st) RETURN(RC_FAIL);\r
1724         }\r
1725 \r
1726         ASN_DEBUG("PER Decoding %s size %ld .. %ld bits %d",\r
1727                 csiz->flags & APC_EXTENSIBLE ? "extensible" : "non-extensible",\r
1728                 csiz->lower_bound, csiz->upper_bound, csiz->effective_bits);\r
1729 \r
1730         if(csiz->flags & APC_EXTENSIBLE) {\r
1731                 int inext = per_get_few_bits(pd, 1);\r
1732                 if(inext < 0) RETURN(RC_WMORE);\r
1733                 if(inext) {\r
1734                         csiz = &asn_DEF_OCTET_STRING_constraints.size;\r
1735                         cval = &asn_DEF_OCTET_STRING_constraints.value;\r
1736                         unit_bits = canonical_unit_bits;\r
1737                 }\r
1738         }\r
1739 \r
1740         if(csiz->effective_bits >= 0) {\r
1741                 FREEMEM(st->buf);\r
1742                 if(bpc) {\r
1743                         st->size = csiz->upper_bound * bpc;\r
1744                 } else {\r
1745                         st->size = (csiz->upper_bound + 7) >> 3;\r
1746                 }\r
1747                 st->buf = (uint8_t *)MALLOC(st->size + 1);\r
1748                 if(!st->buf) { st->size = 0; RETURN(RC_FAIL); }\r
1749         }\r
1750 \r
1751         /* X.691, #16.5: zero-length encoding */\r
1752         /* X.691, #16.6: short fixed length encoding (up to 2 octets) */\r
1753         /* X.691, #16.7: long fixed length encoding (up to 64K octets) */\r
1754         if(csiz->effective_bits == 0) {\r
1755                 int ret;\r
1756                 if (st->size > 2) { /* X.691 #16 NOTE 1 */\r
1757                         if (aper_get_align(pd) < 0)\r
1758                                 RETURN(RC_FAIL);\r
1759                 }\r
1760                 if(bpc) {\r
1761                         ASN_DEBUG("Decoding OCTET STRING size %ld",\r
1762                                 csiz->upper_bound);\r
1763                         ret = OCTET_STRING_per_get_characters(pd, st->buf,\r
1764                                 csiz->upper_bound, bpc, unit_bits,\r
1765                                 cval->lower_bound, cval->upper_bound, pc);\r
1766                         if(ret > 0) RETURN(RC_FAIL);\r
1767                 } else {\r
1768                         ASN_DEBUG("Decoding BIT STRING size %ld",\r
1769                                 csiz->upper_bound);\r
1770                         ret = per_get_many_bits(pd, st->buf, 0,\r
1771                                             unit_bits * csiz->upper_bound);\r
1772                 }\r
1773                 if(ret < 0) RETURN(RC_WMORE);\r
1774                 consumed_myself += unit_bits * csiz->upper_bound;\r
1775                 st->buf[st->size] = 0;\r
1776                 if(bpc == 0) {\r
1777                         int ubs = (csiz->upper_bound & 0x7);\r
1778                         st->bits_unused = ubs ? 8 - ubs : 0;\r
1779                 }\r
1780                 RETURN(RC_OK);\r
1781         }\r
1782 \r
1783         st->size = 0;\r
1784         do {\r
1785                 ssize_t raw_len;\r
1786                 ssize_t len_bytes;\r
1787                 ssize_t len_bits;\r
1788                 void *p;\r
1789                 int ret;\r
1790 \r
1791                 /* Get the PER length */\r
1792                 if (csiz->upper_bound - csiz->lower_bound == 0)\r
1793                         /* Indefinite length case */\r
1794                         raw_len = aper_get_length(pd, -1, csiz->effective_bits, &repeat);\r
1795                 else\r
1796                         raw_len = aper_get_length(pd, csiz->upper_bound - csiz->lower_bound + 1, csiz->effective_bits, &repeat);\r
1797                 repeat = 0;\r
1798                 if(raw_len < 0) RETURN(RC_WMORE);\r
1799                 raw_len += csiz->lower_bound;\r
1800 \r
1801                 ASN_DEBUG("Got PER length eb %ld, len %ld, %s (%s)",\r
1802                         (long)csiz->effective_bits, (long)raw_len,\r
1803                         repeat ? "repeat" : "once", td->name);\r
1804 \r
1805                 if (raw_len > 2) { /* X.691 #16 NOTE 1 */\r
1806                         if (aper_get_align(pd) < 0)\r
1807                                 RETURN(RC_FAIL);\r
1808                 }\r
1809 \r
1810                 if(bpc) {\r
1811                         len_bytes = raw_len * bpc;\r
1812                         len_bits = len_bytes * unit_bits;\r
1813                 } else {\r
1814                         len_bits = raw_len;\r
1815                         len_bytes = (len_bits + 7) >> 3;\r
1816                         if(len_bits & 0x7)\r
1817                                 st->bits_unused = 8 - (len_bits & 0x7);\r
1818                         /* len_bits be multiple of 16K if repeat is set */\r
1819                 }\r
1820                 p = REALLOC(st->buf, st->size + len_bytes + 1);\r
1821                 if(!p) RETURN(RC_FAIL);\r
1822                 st->buf = (uint8_t *)p;\r
1823 \r
1824                 if(bpc) {\r
1825                         ret = OCTET_STRING_per_get_characters(pd,\r
1826                                 &st->buf[st->size], raw_len, bpc, unit_bits,\r
1827                                 cval->lower_bound, cval->upper_bound, pc);\r
1828                         if(ret > 0) RETURN(RC_FAIL);\r
1829                 } else {\r
1830                         ret = per_get_many_bits(pd, &st->buf[st->size],\r
1831                                 0, len_bits);\r
1832                 }\r
1833                 if(ret < 0) RETURN(RC_WMORE);\r
1834                 st->size += len_bytes;\r
1835         } while(repeat);\r
1836         st->buf[st->size] = 0;  /* nul-terminate */\r
1837 \r
1838         return rval;\r
1839 }\r
1840 \r
1841 asn_enc_rval_t\r
1842 OCTET_STRING_encode_aper(const asn_TYPE_descriptor_t *td,\r
1843                          const asn_per_constraints_t *constraints,\r
1844                          const void *sptr, asn_per_outp_t *po) {\r
1845 \r
1846         const asn_OCTET_STRING_specifics_t *specs = td->specifics\r
1847                 ? (const asn_OCTET_STRING_specifics_t *)td->specifics\r
1848                 : &asn_SPC_OCTET_STRING_specs;\r
1849         const asn_per_constraints_t *pc = constraints ? constraints\r
1850         : td->encoding_constraints.per_constraints;\r
1851         const asn_per_constraint_t *cval;\r
1852         const asn_per_constraint_t *csiz;\r
1853         const BIT_STRING_t *st = (const BIT_STRING_t *)sptr;\r
1854         asn_enc_rval_t er = { 0, 0, 0 };\r
1855         int inext = 0;          /* Lies not within extension root */\r
1856         unsigned int unit_bits;\r
1857         unsigned int canonical_unit_bits;\r
1858         unsigned int sizeinunits;\r
1859         const uint8_t *buf;\r
1860         int ret;\r
1861         enum {\r
1862                 OS__BPC_BIT     = 0,\r
1863                 OS__BPC_CHAR    = 1,\r
1864                 OS__BPC_U16     = 2,\r
1865                 OS__BPC_U32     = 4\r
1866         } bpc;  /* Bytes per character */\r
1867         int ct_extensible;\r
1868 \r
1869         if(!st || (!st->buf && st->size))\r
1870                 ASN__ENCODE_FAILED;\r
1871 \r
1872         if(pc) {\r
1873                 cval = &pc->value;\r
1874                 csiz = &pc->size;\r
1875         } else {\r
1876                 cval = &asn_DEF_OCTET_STRING_constraints.value;\r
1877                 csiz = &asn_DEF_OCTET_STRING_constraints.size;\r
1878         }\r
1879         ct_extensible = csiz->flags & APC_EXTENSIBLE;\r
1880 \r
1881         switch(specs->subvariant) {\r
1882                 default:\r
1883                         /*         case ASN_OSUBV_ANY:\r
1884                                          ASN__ENCODE_FAILED;\r
1885                         */\r
1886                 case ASN_OSUBV_BIT:\r
1887                         canonical_unit_bits = unit_bits = 1;\r
1888                         bpc = OS__BPC_BIT;\r
1889                         sizeinunits = st->size * 8 - (st->bits_unused & 0x07);\r
1890                         ASN_DEBUG("BIT STRING of %d bytes",\r
1891                                                                 sizeinunits);\r
1892                 break;\r
1893         case ASN_OSUBV_ANY:\r
1894         case ASN_OSUBV_STR:\r
1895                 canonical_unit_bits = unit_bits = 8;\r
1896 /*              if(cval->flags & APC_CONSTRAINED)\r
1897                         unit_bits = 8;\r
1898 */\r
1899                 bpc = OS__BPC_CHAR;\r
1900                 sizeinunits = st->size;\r
1901                 break;\r
1902         case ASN_OSUBV_U16:\r
1903                 canonical_unit_bits = unit_bits = 16;\r
1904                 if(cval->flags & APC_CONSTRAINED)\r
1905                         unit_bits = cval->range_bits;\r
1906                 bpc = OS__BPC_U16;\r
1907                 sizeinunits = st->size / 2;\r
1908                 break;\r
1909         case ASN_OSUBV_U32:\r
1910                 canonical_unit_bits = unit_bits = 32;\r
1911                 if(cval->flags & APC_CONSTRAINED)\r
1912                         unit_bits = cval->range_bits;\r
1913                 bpc = OS__BPC_U32;\r
1914                 sizeinunits = st->size / 4;\r
1915                 break;\r
1916         }\r
1917 \r
1918         ASN_DEBUG("Encoding %s into %d units of %d bits"\r
1919                 " (%ld..%ld, effective %d)%s",\r
1920                 td->name, sizeinunits, unit_bits,\r
1921                 csiz->lower_bound, csiz->upper_bound,\r
1922                 csiz->effective_bits, ct_extensible ? " EXT" : "");\r
1923 \r
1924         /* Figure out wheter size lies within PER visible constraint */\r
1925 \r
1926         if(csiz->effective_bits >= 0) {\r
1927                 if((int)sizeinunits < csiz->lower_bound\r
1928                 || (int)sizeinunits > csiz->upper_bound) {\r
1929                         if(ct_extensible) {\r
1930                                 cval = &asn_DEF_OCTET_STRING_constraints.value;\r
1931                                 csiz = &asn_DEF_OCTET_STRING_constraints.size;\r
1932                                 unit_bits = canonical_unit_bits;\r
1933                                 inext = 1;\r
1934                         } else\r
1935                                 ASN__ENCODE_FAILED;\r
1936                 }\r
1937         } else {\r
1938                 inext = 0;\r
1939         }\r
1940 \r
1941 \r
1942         if(ct_extensible) {\r
1943                 /* Declare whether length is [not] within extension root */\r
1944                 if(per_put_few_bits(po, inext, 1))\r
1945                         ASN__ENCODE_FAILED;\r
1946         }\r
1947 \r
1948         /* X.691, #16.5: zero-length encoding */\r
1949         /* X.691, #16.6: short fixed length encoding (up to 2 octets) */\r
1950         /* X.691, #16.7: long fixed length encoding (up to 64K octets) */\r
1951         if(csiz->effective_bits >= 0) {\r
1952                 ASN_DEBUG("Encoding %lu bytes (%ld), length in %d bits",\r
1953                                 st->size, sizeinunits - csiz->lower_bound,\r
1954                                 csiz->effective_bits);\r
1955                 if (csiz->effective_bits > 0) {\r
1956                         ret = aper_put_length(po, csiz->upper_bound - csiz->lower_bound + 1, sizeinunits - csiz->lower_bound);\r
1957                         if(ret) ASN__ENCODE_FAILED;\r
1958                 }\r
1959                 if (st->size > 2) { /* X.691 #16 NOTE 1 */\r
1960                         if (aper_put_align(po) < 0)\r
1961                                 ASN__ENCODE_FAILED;\r
1962                 }\r
1963                 if(bpc) {\r
1964                         ret = OCTET_STRING_per_put_characters(po, st->buf,\r
1965                                 sizeinunits, bpc, unit_bits,\r
1966                                 cval->lower_bound, cval->upper_bound, pc);\r
1967                 } else {\r
1968                         ret = per_put_many_bits(po, st->buf,\r
1969                                 sizeinunits * unit_bits);\r
1970                 }\r
1971                 if(ret) ASN__ENCODE_FAILED;\r
1972                 ASN__ENCODED_OK(er);\r
1973         }\r
1974 \r
1975         ASN_DEBUG("Encoding %lu bytes", st->size);\r
1976 \r
1977         if(sizeinunits == 0) {\r
1978                 if(aper_put_length(po, -1, 0))\r
1979                         ASN__ENCODE_FAILED;\r
1980                 ASN__ENCODED_OK(er);\r
1981         }\r
1982 \r
1983         buf = st->buf;\r
1984         while(sizeinunits) {\r
1985                 ssize_t maySave = aper_put_length(po, -1, sizeinunits);\r
1986 \r
1987                 if(maySave < 0) ASN__ENCODE_FAILED;\r
1988 \r
1989                 ASN_DEBUG("Encoding %ld of %ld",\r
1990                         (long)maySave, (long)sizeinunits);\r
1991 \r
1992                 if(bpc) {\r
1993                         ret = OCTET_STRING_per_put_characters(po, buf,\r
1994                                 maySave, bpc, unit_bits,\r
1995                                 cval->lower_bound, cval->upper_bound, pc);\r
1996                 } else {\r
1997                         ret = per_put_many_bits(po, buf, maySave * unit_bits);\r
1998                 }\r
1999                 if(ret) ASN__ENCODE_FAILED;\r
2000 \r
2001                 if(bpc)\r
2002                         buf += maySave * bpc;\r
2003                 else\r
2004                         buf += maySave >> 3;\r
2005                 sizeinunits -= maySave;\r
2006                 assert(!(maySave & 0x07) || !sizeinunits);\r
2007         }\r
2008 \r
2009         ASN__ENCODED_OK(er);\r
2010 }\r
2011 \r
2012 #endif  /* ASN_DISABLE_PER_SUPPORT */\r
2013 \r
2014 int\r
2015 OCTET_STRING_print(const asn_TYPE_descriptor_t *td, const void *sptr,\r
2016                    int ilevel, asn_app_consume_bytes_f *cb, void *app_key) {\r
2017     const char * const h2c = "0123456789ABCDEF";\r
2018         const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr;\r
2019         char scratch[16 * 3 + 4];\r
2020         char *p = scratch;\r
2021         uint8_t *buf;\r
2022         uint8_t *end;\r
2023         size_t i;\r
2024 \r
2025         (void)td;       /* Unused argument */\r
2026 \r
2027         if(!st || (!st->buf && st->size))\r
2028                 return (cb("<absent>", 8, app_key) < 0) ? -1 : 0;\r
2029 \r
2030         /*\r
2031          * Dump the contents of the buffer in hexadecimal.\r
2032          */\r
2033         buf = st->buf;\r
2034         end = buf + st->size;\r
2035         for(i = 0; buf < end; buf++, i++) {\r
2036                 if(!(i % 16) && (i || st->size > 16)) {\r
2037                         if(cb(scratch, p - scratch, app_key) < 0)\r
2038                                 return -1;\r
2039                         _i_INDENT(1);\r
2040                         p = scratch;\r
2041                 }\r
2042                 *p++ = h2c[(*buf >> 4) & 0x0F];\r
2043                 *p++ = h2c[*buf & 0x0F];\r
2044                 *p++ = 0x20;\r
2045         }\r
2046 \r
2047         if(p > scratch) {\r
2048                 p--;    /* Remove the tail space */\r
2049                 if(cb(scratch, p - scratch, app_key) < 0)\r
2050                         return -1;\r
2051         }\r
2052 \r
2053         return 0;\r
2054 }\r
2055 \r
2056 int\r
2057 OCTET_STRING_print_utf8(const asn_TYPE_descriptor_t *td, const void *sptr,\r
2058                         int ilevel, asn_app_consume_bytes_f *cb,\r
2059                         void *app_key) {\r
2060     const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr;\r
2061 \r
2062         (void)td;       /* Unused argument */\r
2063         (void)ilevel;   /* Unused argument */\r
2064 \r
2065         if(st && (st->buf || !st->size)) {\r
2066                 return (cb(st->buf, st->size, app_key) < 0) ? -1 : 0;\r
2067         } else {\r
2068                 return (cb("<absent>", 8, app_key) < 0) ? -1 : 0;\r
2069         }\r
2070 }\r
2071 \r
2072 void\r
2073 OCTET_STRING_free(const asn_TYPE_descriptor_t *td, void *sptr,\r
2074                   enum asn_struct_free_method method) {\r
2075         OCTET_STRING_t *st = (OCTET_STRING_t *)sptr;\r
2076         const asn_OCTET_STRING_specifics_t *specs;\r
2077         asn_struct_ctx_t *ctx;\r
2078         struct _stack *stck;\r
2079 \r
2080         if(!td || !st)\r
2081                 return;\r
2082 \r
2083         specs = td->specifics\r
2084                     ? (const asn_OCTET_STRING_specifics_t *)td->specifics\r
2085                     : &asn_SPC_OCTET_STRING_specs;\r
2086         ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset);\r
2087 \r
2088         ASN_DEBUG("Freeing %s as OCTET STRING", td->name);\r
2089 \r
2090         if(st->buf) {\r
2091                 FREEMEM(st->buf);\r
2092                 st->buf = 0;\r
2093         }\r
2094 \r
2095         /*\r
2096          * Remove decode-time stack.\r
2097          */\r
2098         stck = (struct _stack *)ctx->ptr;\r
2099         if(stck) {\r
2100                 while(stck->tail) {\r
2101                         struct _stack_el *sel = stck->tail;\r
2102                         stck->tail = sel->prev;\r
2103                         FREEMEM(sel);\r
2104                 }\r
2105                 FREEMEM(stck);\r
2106         }\r
2107 \r
2108     switch(method) {\r
2109     case ASFM_FREE_EVERYTHING:\r
2110         FREEMEM(sptr);\r
2111         break;\r
2112     case ASFM_FREE_UNDERLYING:\r
2113         break;\r
2114     case ASFM_FREE_UNDERLYING_AND_RESET:\r
2115         memset(sptr, 0,\r
2116                td->specifics\r
2117                    ? ((const asn_OCTET_STRING_specifics_t *)(td->specifics))\r
2118                          ->struct_size\r
2119                    : sizeof(OCTET_STRING_t));\r
2120         break;\r
2121     }\r
2122 }\r
2123 \r
2124 /*\r
2125  * Conversion routines.\r
2126  */\r
2127 int\r
2128 OCTET_STRING_fromBuf(OCTET_STRING_t *st, const char *str, int len) {\r
2129         void *buf;\r
2130 \r
2131         if(st == 0 || (str == 0 && len)) {\r
2132                 errno = EINVAL;\r
2133                 return -1;\r
2134         }\r
2135 \r
2136         /*\r
2137          * Clear the OCTET STRING.\r
2138          */\r
2139         if(str == NULL) {\r
2140                 FREEMEM(st->buf);\r
2141                 st->buf = 0;\r
2142                 st->size = 0;\r
2143                 return 0;\r
2144         }\r
2145 \r
2146         /* Determine the original string size, if not explicitly given */\r
2147         if(len < 0)\r
2148                 len = strlen(str);\r
2149 \r
2150         /* Allocate and fill the memory */\r
2151         buf = MALLOC(len + 1);\r
2152         if(buf == NULL)\r
2153                 return -1;\r
2154 \r
2155         memcpy(buf, str, len);\r
2156         ((uint8_t *)buf)[len] = '\0';   /* Couldn't use memcpy(len+1)! */\r
2157         FREEMEM(st->buf);\r
2158         st->buf = (uint8_t *)buf;\r
2159         st->size = len;\r
2160 \r
2161         return 0;\r
2162 }\r
2163 \r
2164 OCTET_STRING_t *\r
2165 OCTET_STRING_new_fromBuf(const asn_TYPE_descriptor_t *td, const char *str,\r
2166                          int len) {\r
2167     const asn_OCTET_STRING_specifics_t *specs =\r
2168         td->specifics ? (const asn_OCTET_STRING_specifics_t *)td->specifics\r
2169                       : &asn_SPC_OCTET_STRING_specs;\r
2170     OCTET_STRING_t *st;\r
2171 \r
2172         st = (OCTET_STRING_t *)CALLOC(1, specs->struct_size);\r
2173         if(st && str && OCTET_STRING_fromBuf(st, str, len)) {\r
2174                 FREEMEM(st);\r
2175                 st = NULL;\r
2176         }\r
2177 \r
2178         return st;\r
2179 }\r
2180 \r
2181 /*\r
2182  * Lexicographically compare the common prefix of both strings,\r
2183  * and if it is the same return -1 for the smallest string.\r
2184  */\r
2185 int\r
2186 OCTET_STRING_compare(const asn_TYPE_descriptor_t *td, const void *aptr,\r
2187                      const void *bptr) {\r
2188     const asn_OCTET_STRING_specifics_t *specs = td->specifics;\r
2189     const OCTET_STRING_t *a = aptr;\r
2190     const OCTET_STRING_t *b = bptr;\r
2191 \r
2192     assert(!specs || specs->subvariant != ASN_OSUBV_BIT);\r
2193 \r
2194     if(a && b) {\r
2195         size_t common_prefix_size = a->size <= b->size ? a->size : b->size;\r
2196         int ret = memcmp(a->buf, b->buf, common_prefix_size);\r
2197         if(ret == 0) {\r
2198             /* Figure out which string with equal prefixes is longer. */\r
2199             if(a->size < b->size) {\r
2200                 return -1;\r
2201             } else if(a->size > b->size) {\r
2202                 return 1;\r
2203             } else {\r
2204                 return 0;\r
2205             }\r
2206         } else {\r
2207             return ret < 0 ? -1 : 1;\r
2208         }\r
2209     } else if(!a && !b) {\r
2210         return 0;\r
2211     } else if(!a) {\r
2212         return -1;\r
2213     } else {\r
2214         return 1;\r
2215     }\r
2216 \r
2217 }\r
2218 \r
2219 /*\r
2220  * Biased function for randomizing character values around their limits.\r
2221  */\r
2222 static uint32_t\r
2223 OCTET_STRING__random_char(unsigned long lb, unsigned long ub) {\r
2224     assert(lb <= ub);\r
2225     switch(asn_random_between(0, 16)) {\r
2226     case 0:\r
2227         if(lb < ub) return lb + 1;\r
2228         /* Fall through */\r
2229     case 1:\r
2230         return lb;\r
2231     case 2:\r
2232         if(lb < ub) return ub - 1;\r
2233         /* Fall through */\r
2234     case 3:\r
2235         return ub;\r
2236     default:\r
2237         return asn_random_between(lb, ub);\r
2238     }\r
2239 }\r
2240 \r
2241 \r
2242 size_t\r
2243 OCTET_STRING_random_length_constrained(\r
2244     const asn_TYPE_descriptor_t *td,\r
2245     const asn_encoding_constraints_t *constraints, size_t max_length) {\r
2246     const unsigned lengths[] = {0,     1,     2,     3,     4,     8,\r
2247                                 126,   127,   128,   16383, 16384, 16385,\r
2248                                 65534, 65535, 65536, 65537};\r
2249     size_t rnd_len;\r
2250 \r
2251     /* Figure out how far we should go */\r
2252     rnd_len = lengths[asn_random_between(\r
2253         0, sizeof(lengths) / sizeof(lengths[0]) - 1)];\r
2254 \r
2255     if(!constraints || !constraints->per_constraints)\r
2256         constraints = &td->encoding_constraints;\r
2257     if(constraints->per_constraints) {\r
2258         const asn_per_constraint_t *pc = &constraints->per_constraints->size;\r
2259         if(pc->flags & APC_CONSTRAINED) {\r
2260             long suggested_upper_bound = pc->upper_bound < (ssize_t)max_length\r
2261                                              ? pc->upper_bound\r
2262                                              : (ssize_t)max_length;\r
2263             if(max_length <= (size_t)pc->lower_bound) {\r
2264                 return pc->lower_bound;\r
2265             }\r
2266             if(pc->flags & APC_EXTENSIBLE) {\r
2267                 switch(asn_random_between(0, 5)) {\r
2268                 case 0:\r
2269                     if(pc->lower_bound > 0) {\r
2270                         rnd_len = pc->lower_bound - 1;\r
2271                         break;\r
2272                     }\r
2273                     /* Fall through */\r
2274                 case 1:\r
2275                     rnd_len = pc->upper_bound + 1;\r
2276                     break;\r
2277                 case 2:\r
2278                     /* Keep rnd_len from the table */\r
2279                     if(rnd_len <= max_length) {\r
2280                         break;\r
2281                     }\r
2282                     /* Fall through */\r
2283                 default:\r
2284                     rnd_len = asn_random_between(pc->lower_bound,\r
2285                                                  suggested_upper_bound);\r
2286                 }\r
2287             } else {\r
2288                 rnd_len =\r
2289                     asn_random_between(pc->lower_bound, suggested_upper_bound);\r
2290             }\r
2291         } else {\r
2292             rnd_len = asn_random_between(0, max_length);\r
2293         }\r
2294     } else if(rnd_len > max_length) {\r
2295         rnd_len = asn_random_between(0, max_length);\r
2296     }\r
2297 \r
2298     return rnd_len;\r
2299 }\r
2300 \r
2301 asn_random_fill_result_t\r
2302 OCTET_STRING_random_fill(const asn_TYPE_descriptor_t *td, void **sptr,\r
2303                          const asn_encoding_constraints_t *constraints,\r
2304                          size_t max_length) {\r
2305         const asn_OCTET_STRING_specifics_t *specs = td->specifics\r
2306                                 ? (const asn_OCTET_STRING_specifics_t *)td->specifics\r
2307                                 : &asn_SPC_OCTET_STRING_specs;\r
2308     asn_random_fill_result_t result_ok = {ARFILL_OK, 1};\r
2309     asn_random_fill_result_t result_failed = {ARFILL_FAILED, 0};\r
2310     asn_random_fill_result_t result_skipped = {ARFILL_SKIPPED, 0};\r
2311     unsigned int unit_bytes = 1;\r
2312     unsigned long clb = 0;  /* Lower bound on char */\r
2313     unsigned long cub = 255;  /* Higher bound on char value */\r
2314     uint8_t *buf;\r
2315     uint8_t *bend;\r
2316     uint8_t *b;\r
2317     size_t rnd_len;\r
2318     OCTET_STRING_t *st;\r
2319 \r
2320     if(max_length == 0 && !*sptr) return result_skipped;\r
2321 \r
2322     switch(specs->subvariant) {\r
2323     default:\r
2324     case ASN_OSUBV_ANY:\r
2325         return result_failed;\r
2326     case ASN_OSUBV_BIT:\r
2327         /* Handled by BIT_STRING itself. */\r
2328         return result_failed;\r
2329     case ASN_OSUBV_STR:\r
2330         unit_bytes = 1;\r
2331         clb = 0;\r
2332         cub = 255;\r
2333         break;\r
2334     case ASN_OSUBV_U16:\r
2335         unit_bytes = 2;\r
2336         clb = 0;\r
2337         cub = 65535;\r
2338         break;\r
2339     case ASN_OSUBV_U32:\r
2340         unit_bytes = 4;\r
2341         clb = 0;\r
2342         cub = 0x10FFFF;\r
2343         break;\r
2344     }\r
2345 \r
2346     if(!constraints || !constraints->per_constraints)\r
2347         constraints = &td->encoding_constraints;\r
2348     if(constraints->per_constraints) {\r
2349         const asn_per_constraint_t *pc = &constraints->per_constraints->value;\r
2350         if(pc->flags & APC_SEMI_CONSTRAINED) {\r
2351             clb = pc->lower_bound;\r
2352         } else if(pc->flags & APC_CONSTRAINED) {\r
2353             clb = pc->lower_bound;\r
2354             cub = pc->upper_bound;\r
2355         }\r
2356     }\r
2357 \r
2358     rnd_len =\r
2359         OCTET_STRING_random_length_constrained(td, constraints, max_length);\r
2360 \r
2361     buf = CALLOC(unit_bytes, rnd_len + 1);\r
2362     if(!buf) return result_failed;\r
2363 \r
2364     bend = &buf[unit_bytes * rnd_len];\r
2365 \r
2366     switch(unit_bytes) {\r
2367     case 1:\r
2368         for(b = buf; b < bend; b += unit_bytes) {\r
2369             *(uint8_t *)b = OCTET_STRING__random_char(clb, cub);\r
2370         }\r
2371         *(uint8_t *)b = 0;\r
2372         break;\r
2373     case 2:\r
2374         for(b = buf; b < bend; b += unit_bytes) {\r
2375             uint32_t code = OCTET_STRING__random_char(clb, cub);\r
2376             b[0] = code >> 8;\r
2377             b[1] = code;\r
2378         }\r
2379         *(uint16_t *)b = 0;\r
2380         break;\r
2381     case 4:\r
2382         for(b = buf; b < bend; b += unit_bytes) {\r
2383             uint32_t code = OCTET_STRING__random_char(clb, cub);\r
2384             b[0] = code >> 24;\r
2385             b[1] = code >> 16;\r
2386             b[2] = code >> 8;\r
2387             b[3] = code;\r
2388         }\r
2389         *(uint32_t *)b = 0;\r
2390         break;\r
2391     }\r
2392 \r
2393     if(*sptr) {\r
2394         st = *sptr;\r
2395         FREEMEM(st->buf);\r
2396     } else {\r
2397         st = (OCTET_STRING_t *)(*sptr = CALLOC(1, specs->struct_size));\r
2398         if(!st) {\r
2399             FREEMEM(buf);\r
2400             return result_failed;\r
2401         }\r
2402     }\r
2403 \r
2404     st->buf = buf;\r
2405     st->size = unit_bytes * rnd_len;\r
2406 \r
2407     result_ok.length = st->size;\r
2408     return result_ok;\r
2409 }\r