2 * Copyright (c) 2017 Lev Walkin <vlm@lionet.info>.
4 * Redistribution and modifications are permitted subject to BSD license.
6 #include <asn_internal.h>
7 #include <OCTET_STRING.h>
8 #include <BIT_STRING.h> /* for .bits_unused member */
11 OCTET_STRING_encode_xer(const asn_TYPE_descriptor_t *td, const void *sptr,
12 int ilevel, enum xer_encoder_flags_e flags,
13 asn_app_consume_bytes_f *cb, void *app_key) {
14 const char * const h2c = "0123456789ABCDEF";
15 const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr;
16 asn_enc_rval_t er = { 0, 0, 0 };
17 char scratch[16 * 3 + 4];
23 if(!st || (!st->buf && st->size))
29 * Dump the contents of the buffer in hexadecimal.
33 if(flags & XER_F_CANONICAL) {
34 char *scend = scratch + (sizeof(scratch) - 2);
35 for(; buf < end; buf++) {
37 ASN__CALLBACK(scratch, p - scratch);
40 *p++ = h2c[(*buf >> 4) & 0x0F];
41 *p++ = h2c[*buf & 0x0F];
44 ASN__CALLBACK(scratch, p-scratch); /* Dump the rest */
46 for(i = 0; buf < end; buf++, i++) {
47 if(!(i % 16) && (i || st->size > 16)) {
48 ASN__CALLBACK(scratch, p-scratch);
50 ASN__TEXT_INDENT(1, ilevel);
52 *p++ = h2c[(*buf >> 4) & 0x0F];
53 *p++ = h2c[*buf & 0x0F];
57 p--; /* Remove the tail space */
58 ASN__CALLBACK(scratch, p-scratch); /* Dump the rest */
60 ASN__TEXT_INDENT(1, ilevel-1);
69 static const struct OCTET_STRING__xer_escape_table_s {
72 } OCTET_STRING__xer_escape_table[] = {
73 #define OSXET(s) { s, sizeof(s) - 1 }
74 OSXET("\074\156\165\154\057\076"), /* <nul/> */
75 OSXET("\074\163\157\150\057\076"), /* <soh/> */
76 OSXET("\074\163\164\170\057\076"), /* <stx/> */
77 OSXET("\074\145\164\170\057\076"), /* <etx/> */
78 OSXET("\074\145\157\164\057\076"), /* <eot/> */
79 OSXET("\074\145\156\161\057\076"), /* <enq/> */
80 OSXET("\074\141\143\153\057\076"), /* <ack/> */
81 OSXET("\074\142\145\154\057\076"), /* <bel/> */
82 OSXET("\074\142\163\057\076"), /* <bs/> */
83 OSXET("\011"), /* \t */
84 OSXET("\012"), /* \n */
85 OSXET("\074\166\164\057\076"), /* <vt/> */
86 OSXET("\074\146\146\057\076"), /* <ff/> */
87 OSXET("\015"), /* \r */
88 OSXET("\074\163\157\057\076"), /* <so/> */
89 OSXET("\074\163\151\057\076"), /* <si/> */
90 OSXET("\074\144\154\145\057\076"), /* <dle/> */
91 OSXET("\074\144\143\061\057\076"), /* <de1/> */
92 OSXET("\074\144\143\062\057\076"), /* <de2/> */
93 OSXET("\074\144\143\063\057\076"), /* <de3/> */
94 OSXET("\074\144\143\064\057\076"), /* <de4/> */
95 OSXET("\074\156\141\153\057\076"), /* <nak/> */
96 OSXET("\074\163\171\156\057\076"), /* <syn/> */
97 OSXET("\074\145\164\142\057\076"), /* <etb/> */
98 OSXET("\074\143\141\156\057\076"), /* <can/> */
99 OSXET("\074\145\155\057\076"), /* <em/> */
100 OSXET("\074\163\165\142\057\076"), /* <sub/> */
101 OSXET("\074\145\163\143\057\076"), /* <esc/> */
102 OSXET("\074\151\163\064\057\076"), /* <is4/> */
103 OSXET("\074\151\163\063\057\076"), /* <is3/> */
104 OSXET("\074\151\163\062\057\076"), /* <is2/> */
105 OSXET("\074\151\163\061\057\076"), /* <is1/> */
112 OSXET("\046\141\155\160\073"), /* & */
114 {0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, /* ()*+,-./ */
115 {0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, /* 01234567 */
116 {0,0},{0,0},{0,0},{0,0}, /* 89:; */
117 OSXET("\046\154\164\073"), /* < */
119 OSXET("\046\147\164\073"), /* > */
123 OS__check_escaped_control_char(const void *buf, int size) {
126 * Inefficient algorithm which translates the escape sequences
127 * defined above into characters. Returns -1 if not found.
128 * TODO: replace by a faster algorithm (bsearch(), hash or
129 * nested table lookups).
131 for(i = 0; i < 32 /* Don't spend time on the bottom half */; i++) {
132 const struct OCTET_STRING__xer_escape_table_s *el;
133 el = &OCTET_STRING__xer_escape_table[i];
134 if(el->size == size && memcmp(buf, el->string, size) == 0)
141 OCTET_STRING__handle_control_chars(void *struct_ptr, const void *chunk_buf, size_t chunk_size) {
143 * This might be one of the escape sequences
144 * for control characters. Check it out.
147 int control_char = OS__check_escaped_control_char(chunk_buf,chunk_size);
148 if(control_char >= 0) {
149 OCTET_STRING_t *st = (OCTET_STRING_t *)struct_ptr;
150 void *p = REALLOC(st->buf, st->size + 2);
152 st->buf = (uint8_t *)p;
153 st->buf[st->size++] = control_char;
154 st->buf[st->size] = '\0'; /* nul-termination */
159 return -1; /* No, it's not */
163 OCTET_STRING_encode_xer_utf8(const asn_TYPE_descriptor_t *td, const void *sptr,
164 int ilevel, enum xer_encoder_flags_e flags,
165 asn_app_consume_bytes_f *cb, void *app_key) {
166 const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr;
167 asn_enc_rval_t er = { 0, 0, 0 };
169 uint8_t *ss; /* Sequence start */
170 ssize_t encoded_len = 0;
172 (void)ilevel; /* Unused argument */
173 (void)flags; /* Unused argument */
175 if(!st || (!st->buf && st->size))
179 end = buf + st->size;
180 for(ss = buf; buf < end; buf++) {
181 unsigned int ch = *buf;
182 int s_len; /* Special encoding sequence length */
185 * Escape certain characters: X.680/11.15
187 if(ch < sizeof(OCTET_STRING__xer_escape_table)
188 / sizeof(OCTET_STRING__xer_escape_table[0])
189 && (s_len = OCTET_STRING__xer_escape_table[ch].size)) {
190 if(((buf - ss) && cb(ss, buf - ss, app_key) < 0)
191 || cb(OCTET_STRING__xer_escape_table[ch].string, s_len, app_key) < 0)
193 encoded_len += (buf - ss) + s_len;
198 encoded_len += (buf - ss);
199 if((buf - ss) && cb(ss, buf - ss, app_key) < 0)
202 er.encoded = encoded_len;
207 * Convert from hexadecimal format (cstring): "AB CD EF"
209 static ssize_t OCTET_STRING__convert_hexadecimal(void *sptr, const void *chunk_buf, size_t chunk_size, int have_more) {
210 OCTET_STRING_t *st = (OCTET_STRING_t *)sptr;
211 const char *chunk_stop = (const char *)chunk_buf;
212 const char *p = chunk_stop;
213 const char *pend = p + chunk_size;
214 unsigned int clv = 0;
215 int half = 0; /* Half bit */
218 /* Reallocate buffer according to high cap estimation */
219 size_t new_size = st->size + (chunk_size + 1) / 2;
220 void *nptr = REALLOC(st->buf, new_size + 1);
222 st->buf = (uint8_t *)nptr;
223 buf = st->buf + st->size;
226 * If something like " a b c " appears here, the " a b":3 will be
227 * converted, and the rest skipped. That is, unless buf_size is greater
228 * than chunk_size, then it'll be equivalent to "ABC0".
230 for(; p < pend; p++) {
231 int ch = *(const unsigned char *)p;
233 case 0x09: case 0x0a: case 0x0c: case 0x0d:
235 /* Ignore whitespace */
237 case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: /*01234*/
238 case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: /*56789*/
239 clv = (clv << 4) + (ch - 0x30);
241 case 0x41: case 0x42: case 0x43: /* ABC */
242 case 0x44: case 0x45: case 0x46: /* DEF */
243 clv = (clv << 4) + (ch - 0x41 + 10);
245 case 0x61: case 0x62: case 0x63: /* abc */
246 case 0x64: case 0x65: case 0x66: /* def */
247 clv = (clv << 4) + (ch - 0x61 + 10);
261 * Check partial decoding.
266 * Partial specification is fine,
267 * because no more more PXER_TEXT data is available.
276 st->size = buf - st->buf; /* Adjust the buffer size */
277 assert(st->size <= new_size);
278 st->buf[st->size] = 0; /* Courtesy termination */
280 return (chunk_stop - (const char *)chunk_buf); /* Converted size */
284 * Convert from binary format: "00101011101"
286 static ssize_t OCTET_STRING__convert_binary(void *sptr, const void *chunk_buf, size_t chunk_size, int have_more) {
287 BIT_STRING_t *st = (BIT_STRING_t *)sptr;
288 const char *p = (const char *)chunk_buf;
289 const char *pend = (p == NULL)? NULL : p + chunk_size;
290 int bits_unused = st->bits_unused & 0x7;
293 /* Reallocate buffer according to high cap estimation */
294 size_t new_size = st->size + (chunk_size + 7) / 8;
295 void *nptr = REALLOC(st->buf, new_size + 1);
297 st->buf = (uint8_t *)nptr;
298 buf = st->buf + st->size;
308 * Convert series of 0 and 1 into the octet string.
310 for(; p < pend; p++) {
311 int ch = *(const unsigned char *)p;
313 case 0x09: case 0x0a: case 0x0c: case 0x0d:
315 /* Ignore whitespace */
319 if(bits_unused-- <= 0) {
320 *++buf = 0; /* Clean the cell */
323 *buf |= (ch&1) << bits_unused;
326 st->bits_unused = bits_unused;
331 if(bits_unused == 8) {
332 st->size = buf - st->buf;
335 st->size = buf - st->buf + 1;
336 st->bits_unused = bits_unused;
339 assert(st->size <= new_size);
340 st->buf[st->size] = 0; /* Courtesy termination */
342 return chunk_size; /* Converted in full */
346 * Something like strtod(), but with stricter rules.
349 OS__strtoent(int base, const char *buf, const char *end, int32_t *ret_value) {
350 const int32_t last_unicode_codepoint = 0x10ffff;
354 for(p = buf; p < end; p++) {
358 case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: /*01234*/
359 case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: /*56789*/
360 val = val * base + (ch - 0x30);
362 case 0x41: case 0x42: case 0x43: /* ABC */
363 case 0x44: case 0x45: case 0x46: /* DEF */
364 val = val * base + (ch - 0x41 + 10);
366 case 0x61: case 0x62: case 0x63: /* abc */
367 case 0x64: case 0x65: case 0x66: /* def */
368 val = val * base + (ch - 0x61 + 10);
372 return (p - buf) + 1;
374 return -1; /* Character set error */
377 /* Value exceeds the Unicode range. */
378 if(val > last_unicode_codepoint) {
388 * Convert from the plain UTF-8 format, expanding entity references: "2 < 3"
391 OCTET_STRING__convert_entrefs(void *sptr, const void *chunk_buf,
392 size_t chunk_size, int have_more) {
393 OCTET_STRING_t *st = (OCTET_STRING_t *)sptr;
394 const char *p = (const char *)chunk_buf;
395 const char *pend = p + chunk_size;
398 /* Reallocate buffer */
399 size_t new_size = st->size + chunk_size;
400 void *nptr = REALLOC(st->buf, new_size + 1);
402 st->buf = (uint8_t *)nptr;
403 buf = st->buf + st->size;
406 * Convert series of 0 and 1 into the octet string.
408 for(; p < pend; p++) {
409 int ch = *(const unsigned char *)p;
410 int len; /* Length of the rest of the chunk */
412 if(ch != 0x26 /* '&' */) {
414 continue; /* That was easy... */
418 * Process entity reference.
420 len = chunk_size - (p - (const char *)chunk_buf);
421 if(len == 1 /* "&" */) goto want_more;
422 if(p[1] == 0x23 /* '#' */) {
423 const char *pval; /* Pointer to start of digits */
424 int32_t val = 0; /* Entity reference value */
427 if(len == 2 /* "&#" */) goto want_more;
428 if(p[2] == 0x78 /* 'x' */)
429 pval = p + 3, base = 16;
431 pval = p + 2, base = 10;
432 len = OS__strtoent(base, pval, p + len, &val);
434 /* Invalid charset. Just copy verbatim. */
438 if(!len || pval[len-1] != 0x3b) goto want_more;
440 p += (pval - p) + len - 1; /* Advance past entref */
444 } else if(val < 0x800) {
445 *buf++ = 0xc0 | ((val >> 6));
446 *buf++ = 0x80 | ((val & 0x3f));
447 } else if(val < 0x10000) {
448 *buf++ = 0xe0 | ((val >> 12));
449 *buf++ = 0x80 | ((val >> 6) & 0x3f);
450 *buf++ = 0x80 | ((val & 0x3f));
451 } else if(val < 0x200000) {
452 *buf++ = 0xf0 | ((val >> 18));
453 *buf++ = 0x80 | ((val >> 12) & 0x3f);
454 *buf++ = 0x80 | ((val >> 6) & 0x3f);
455 *buf++ = 0x80 | ((val & 0x3f));
456 } else if(val < 0x4000000) {
457 *buf++ = 0xf8 | ((val >> 24));
458 *buf++ = 0x80 | ((val >> 18) & 0x3f);
459 *buf++ = 0x80 | ((val >> 12) & 0x3f);
460 *buf++ = 0x80 | ((val >> 6) & 0x3f);
461 *buf++ = 0x80 | ((val & 0x3f));
463 *buf++ = 0xfc | ((val >> 30) & 0x1);
464 *buf++ = 0x80 | ((val >> 24) & 0x3f);
465 *buf++ = 0x80 | ((val >> 18) & 0x3f);
466 *buf++ = 0x80 | ((val >> 12) & 0x3f);
467 *buf++ = 0x80 | ((val >> 6) & 0x3f);
468 *buf++ = 0x80 | ((val & 0x3f));
472 * Ugly, limited parsing of & > <
474 char *sc = (char *)memchr(p, 0x3b, len > 5 ? 5 : len);
475 if(!sc) goto want_more;
477 && p[1] == 0x61 /* 'a' */
478 && p[2] == 0x6d /* 'm' */
479 && p[3] == 0x70 /* 'p' */) {
486 *buf = 0x3c; /* '<' */
487 } else if(p[1] == 0x67) {
488 *buf = 0x3e; /* '>' */
490 /* Unsupported entity reference */
495 /* Unsupported entity reference */
503 /* Unsupported entity reference */
511 * We know that no more data (of the same type)
512 * is coming. Copy the rest verbatim.
517 chunk_size = (p - (const char *)chunk_buf);
518 /* Processing stalled: need more data */
522 st->size = buf - st->buf;
523 assert(st->size <= new_size);
524 st->buf[st->size] = 0; /* Courtesy termination */
526 return chunk_size; /* Converted in full */
530 * Decode OCTET STRING from the XML element's body.
532 static asn_dec_rval_t
533 OCTET_STRING__decode_xer(
534 const asn_codec_ctx_t *opt_codec_ctx, const asn_TYPE_descriptor_t *td,
535 void **sptr, const char *opt_mname, const void *buf_ptr, size_t size,
536 int (*opt_unexpected_tag_decoder)(void *struct_ptr, const void *chunk_buf,
538 ssize_t (*body_receiver)(void *struct_ptr, const void *chunk_buf,
539 size_t chunk_size, int have_more)) {
540 OCTET_STRING_t *st = (OCTET_STRING_t *)*sptr;
541 const asn_OCTET_STRING_specifics_t *specs = td->specifics
542 ? (const asn_OCTET_STRING_specifics_t *)td->specifics
543 : &asn_SPC_OCTET_STRING_specs;
544 const char *xml_tag = opt_mname ? opt_mname : td->xml_tag;
545 asn_struct_ctx_t *ctx; /* Per-structure parser context */
546 asn_dec_rval_t rval; /* Return value from the decoder */
550 * Create the string if does not exist.
553 st = (OCTET_STRING_t *)CALLOC(1, specs->struct_size);
555 if(!st) goto sta_failed;
561 /* This is separate from above section */
562 st->buf = (uint8_t *)CALLOC(1, 1);
573 /* Restore parsing context */
574 ctx = (asn_struct_ctx_t *)(((char *)*sptr) + specs->ctx_offset);
576 return xer_decode_general(opt_codec_ctx, ctx, *sptr, xml_tag,
578 opt_unexpected_tag_decoder,
590 * Decode OCTET STRING from the hexadecimal data.
593 OCTET_STRING_decode_xer_hex(const asn_codec_ctx_t *opt_codec_ctx,
594 const asn_TYPE_descriptor_t *td, void **sptr,
595 const char *opt_mname, const void *buf_ptr,
597 return OCTET_STRING__decode_xer(opt_codec_ctx, td, sptr, opt_mname,
599 OCTET_STRING__convert_hexadecimal);
603 * Decode OCTET STRING from the binary (0/1) data.
606 OCTET_STRING_decode_xer_binary(const asn_codec_ctx_t *opt_codec_ctx,
607 const asn_TYPE_descriptor_t *td, void **sptr,
608 const char *opt_mname, const void *buf_ptr,
610 return OCTET_STRING__decode_xer(opt_codec_ctx, td, sptr, opt_mname,
612 OCTET_STRING__convert_binary);
616 * Decode OCTET STRING from the string (ASCII/UTF-8) data.
619 OCTET_STRING_decode_xer_utf8(const asn_codec_ctx_t *opt_codec_ctx,
620 const asn_TYPE_descriptor_t *td, void **sptr,
621 const char *opt_mname, const void *buf_ptr,
623 return OCTET_STRING__decode_xer(opt_codec_ctx, td, sptr, opt_mname,
625 OCTET_STRING__handle_control_chars,
626 OCTET_STRING__convert_entrefs);