SIM-115: update simulator to use latest E2SM KPM version 3
[sim/e2-interface.git] / e2sim / asn1c / OCTET_STRING_xer.c
1 /*
2  * Copyright (c) 2017 Lev Walkin <vlm@lionet.info>.
3  * All rights reserved.
4  * Redistribution and modifications are permitted subject to BSD license.
5  */
6 #include <asn_internal.h>
7 #include <OCTET_STRING.h>
8 #include <BIT_STRING.h>  /* for .bits_unused member */
9
10 asn_enc_rval_t
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];
18     char *p = scratch;
19     uint8_t *buf;
20     uint8_t *end;
21     size_t i;
22
23     if(!st || (!st->buf && st->size))
24         ASN__ENCODE_FAILED;
25
26     er.encoded = 0;
27
28     /*
29      * Dump the contents of the buffer in hexadecimal.
30      */
31     buf = st->buf;
32     end = buf + st->size;
33     if(flags & XER_F_CANONICAL) {
34         char *scend = scratch + (sizeof(scratch) - 2);
35         for(; buf < end; buf++) {
36             if(p >= scend) {
37                 ASN__CALLBACK(scratch, p - scratch);
38                 p = scratch;
39             }
40             *p++ = h2c[(*buf >> 4) & 0x0F];
41             *p++ = h2c[*buf & 0x0F];
42         }
43
44         ASN__CALLBACK(scratch, p-scratch);  /* Dump the rest */
45     } else {
46         for(i = 0; buf < end; buf++, i++) {
47             if(!(i % 16) && (i || st->size > 16)) {
48                 ASN__CALLBACK(scratch, p-scratch);
49                 p = scratch;
50                 ASN__TEXT_INDENT(1, ilevel);
51             }
52             *p++ = h2c[(*buf >> 4) & 0x0F];
53             *p++ = h2c[*buf & 0x0F];
54             *p++ = 0x20;
55         }
56         if(p - scratch) {
57             p--;  /* Remove the tail space */
58             ASN__CALLBACK(scratch, p-scratch);  /* Dump the rest */
59             if(st->size > 16)
60                 ASN__TEXT_INDENT(1, ilevel-1);
61         }
62     }
63
64     ASN__ENCODED_OK(er);
65 cb_failed:
66     ASN__ENCODE_FAILED;
67 }
68
69 static const struct OCTET_STRING__xer_escape_table_s {
70     const char *string;
71     int size;
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/> */
106     { 0, 0 },                           /* " " */
107     { 0, 0 },                           /* ! */
108     { 0, 0 },                           /* \" */
109     { 0, 0 },                           /* # */
110     { 0, 0 },                           /* $ */
111     { 0, 0 },                           /* % */
112     OSXET("\046\141\155\160\073"),      /* &amp; */
113     { 0, 0 },                           /* ' */
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"),          /* &lt; */
118     { 0, 0 },                           /* = */
119     OSXET("\046\147\164\073"),          /* &gt; */
120 };
121
122 static int
123 OS__check_escaped_control_char(const void *buf, int size) {
124     size_t i;
125     /*
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).
130      */
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)
135             return i;
136     }
137     return -1;
138 }
139
140 static int
141 OCTET_STRING__handle_control_chars(void *struct_ptr, const void *chunk_buf, size_t chunk_size) {
142     /*
143      * This might be one of the escape sequences
144      * for control characters. Check it out.
145      * #11.15.5
146      */
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);
151         if(p) {
152             st->buf = (uint8_t *)p;
153             st->buf[st->size++] = control_char;
154             st->buf[st->size] = '\0';  /* nul-termination */
155             return 0;
156         }
157     }
158
159     return -1;  /* No, it's not */
160 }
161
162 asn_enc_rval_t
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 };
168     uint8_t *buf, *end;
169     uint8_t *ss;  /* Sequence start */
170     ssize_t encoded_len = 0;
171
172     (void)ilevel;  /* Unused argument */
173     (void)flags;  /* Unused argument */
174
175     if(!st || (!st->buf && st->size))
176         ASN__ENCODE_FAILED;
177
178     buf = st->buf;
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 */
183
184         /*
185          * Escape certain characters: X.680/11.15
186          */
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)
192                 ASN__ENCODE_FAILED;
193             encoded_len += (buf - ss) + s_len;
194             ss = buf + 1;
195         }
196     }
197
198     encoded_len += (buf - ss);
199     if((buf - ss) && cb(ss, buf - ss, app_key) < 0)
200         ASN__ENCODE_FAILED;
201
202     er.encoded = encoded_len;
203     ASN__ENCODED_OK(er);
204 }
205
206 /*
207  * Convert from hexadecimal format (cstring): "AB CD EF"
208  */
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 */
216     uint8_t *buf;
217
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);
221     if(!nptr) return -1;
222     st->buf = (uint8_t *)nptr;
223     buf = st->buf + st->size;
224
225     /*
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".
229      */
230     for(; p < pend; p++) {
231         int ch = *(const unsigned char *)p;
232         switch(ch) {
233         case 0x09: case 0x0a: case 0x0c: case 0x0d:
234         case 0x20:
235             /* Ignore whitespace */
236             continue;
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);
240             break;
241         case 0x41: case 0x42: case 0x43:  /* ABC */
242         case 0x44: case 0x45: case 0x46:  /* DEF */
243             clv = (clv << 4) + (ch - 0x41 + 10);
244             break;
245         case 0x61: case 0x62: case 0x63:  /* abc */
246         case 0x64: case 0x65: case 0x66:  /* def */
247             clv = (clv << 4) + (ch - 0x61 + 10);
248             break;
249         default:
250             *buf = 0;  /* JIC */
251             return -1;
252         }
253         if(half++) {
254             half = 0;
255             *buf++ = clv;
256             chunk_stop = p + 1;
257         }
258     }
259
260     /*
261      * Check partial decoding.
262      */
263     if(half) {
264         if(have_more) {
265             /*
266              * Partial specification is fine,
267              * because no more more PXER_TEXT data is available.
268              */
269             *buf++ = clv << 4;
270             chunk_stop = p;
271         }
272     } else {
273         chunk_stop = p;
274     }
275
276     st->size = buf - st->buf;  /* Adjust the buffer size */
277     assert(st->size <= new_size);
278     st->buf[st->size] = 0;  /* Courtesy termination */
279
280     return (chunk_stop - (const char *)chunk_buf);  /* Converted size */
281 }
282
283 /*
284  * Convert from binary format: "00101011101"
285  */
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;
291     uint8_t *buf;
292
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);
296     if(!nptr) return -1;
297     st->buf = (uint8_t *)nptr;
298     buf = st->buf + st->size;
299
300     (void)have_more;
301
302     if(bits_unused == 0)
303         bits_unused = 8;
304     else if(st->size)
305         buf--;
306
307     /*
308      * Convert series of 0 and 1 into the octet string.
309      */
310     for(; p < pend; p++) {
311         int ch = *(const unsigned char *)p;
312         switch(ch) {
313         case 0x09: case 0x0a: case 0x0c: case 0x0d:
314         case 0x20:
315             /* Ignore whitespace */
316             break;
317         case 0x30:
318         case 0x31:
319             if(bits_unused-- <= 0) {
320                 *++buf = 0;     /* Clean the cell */
321                 bits_unused = 7;
322             }
323             *buf |= (ch&1) << bits_unused;
324             break;
325         default:
326             st->bits_unused = bits_unused;
327             return -1;
328         }
329     }
330
331     if(bits_unused == 8) {
332         st->size = buf - st->buf;
333         st->bits_unused = 0;
334     } else {
335         st->size = buf - st->buf + 1;
336         st->bits_unused = bits_unused;
337     }
338
339     assert(st->size <= new_size);
340     st->buf[st->size] = 0;  /* Courtesy termination */
341
342     return chunk_size;  /* Converted in full */
343 }
344
345 /*
346  * Something like strtod(), but with stricter rules.
347  */
348 static int
349 OS__strtoent(int base, const char *buf, const char *end, int32_t *ret_value) {
350         const int32_t last_unicode_codepoint = 0x10ffff;
351         int32_t val = 0;
352         const char *p;
353
354         for(p = buf; p < end; p++) {
355                 int ch = *p;
356
357         switch(ch) {
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);
361             break;
362         case 0x41: case 0x42: case 0x43:  /* ABC */
363         case 0x44: case 0x45: case 0x46:  /* DEF */
364             val = val * base + (ch - 0x41 + 10);
365             break;
366         case 0x61: case 0x62: case 0x63:  /* abc */
367         case 0x64: case 0x65: case 0x66:  /* def */
368             val = val * base + (ch - 0x61 + 10);
369             break;
370         case 0x3b:  /* ';' */
371             *ret_value = val;
372             return (p - buf) + 1;
373         default:
374             return -1;  /* Character set error */
375         }
376
377         /* Value exceeds the Unicode range. */
378         if(val > last_unicode_codepoint) {
379             return -1;
380         }
381     }
382
383     *ret_value = -1;
384     return (p - buf);
385 }
386
387 /*
388  * Convert from the plain UTF-8 format, expanding entity references: "2 &lt; 3"
389  */
390 static ssize_t
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;
396     uint8_t *buf;
397
398     /* Reallocate buffer */
399     size_t new_size = st->size + chunk_size;
400     void *nptr = REALLOC(st->buf, new_size + 1);
401     if(!nptr) return -1;
402     st->buf = (uint8_t *)nptr;
403     buf = st->buf + st->size;
404
405     /*
406      * Convert series of 0 and 1 into the octet string.
407      */
408     for(; p < pend; p++) {
409         int ch = *(const unsigned char *)p;
410         int len;  /* Length of the rest of the chunk */
411
412         if(ch != 0x26 /* '&' */) {
413             *buf++ = ch;
414             continue;  /* That was easy... */
415         }
416
417         /*
418          * Process entity reference.
419          */
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 */
425             int base;
426
427             if(len == 2 /* "&#" */) goto want_more;
428             if(p[2] == 0x78 /* 'x' */)
429                 pval = p + 3, base = 16;
430             else
431                 pval = p + 2, base = 10;
432             len = OS__strtoent(base, pval, p + len, &val);
433             if(len == -1) {
434                 /* Invalid charset. Just copy verbatim. */
435                 *buf++ = ch;
436                 continue;
437             }
438             if(!len || pval[len-1] != 0x3b) goto want_more;
439             assert(val > 0);
440             p += (pval - p) + len - 1;  /* Advance past entref */
441
442             if(val < 0x80) {
443                 *buf++ = (char)val;
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));
462             } else {
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));
469             }
470         } else {
471             /*
472              * Ugly, limited parsing of &amp; &gt; &lt;
473              */
474             char *sc = (char *)memchr(p, 0x3b, len > 5 ? 5 : len);
475             if(!sc) goto want_more;
476             if((sc - p) == 4
477                 && p[1] == 0x61  /* 'a' */
478                 && p[2] == 0x6d  /* 'm' */
479                 && p[3] == 0x70  /* 'p' */) {
480                 *buf++ = 0x26;
481                 p = sc;
482                 continue;
483             }
484             if((sc - p) == 3) {
485                 if(p[1] == 0x6c) {
486                     *buf = 0x3c;  /* '<' */
487                 } else if(p[1] == 0x67) {
488                     *buf = 0x3e;  /* '>' */
489                 } else {
490                     /* Unsupported entity reference */
491                     *buf++ = ch;
492                     continue;
493                 }
494                 if(p[2] != 0x74) {
495                     /* Unsupported entity reference */
496                     *buf++ = ch;
497                     continue;
498                 }
499                 buf++;
500                 p = sc;
501                 continue;
502             }
503             /* Unsupported entity reference */
504             *buf++ = ch;
505         }
506
507         continue;
508     want_more:
509         if(have_more) {
510             /*
511              * We know that no more data (of the same type)
512              * is coming. Copy the rest verbatim.
513              */
514             *buf++ = ch;
515             continue;
516         }
517         chunk_size = (p - (const char *)chunk_buf);
518         /* Processing stalled: need more data */
519         break;
520     }
521
522     st->size = buf - st->buf;
523     assert(st->size <= new_size);
524     st->buf[st->size] = 0;  /* Courtesy termination */
525
526     return chunk_size;  /* Converted in full */
527 }
528
529 /*
530  * Decode OCTET STRING from the XML element's body.
531  */
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,
537                                       size_t chunk_size),
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 */
547     int st_allocated;
548
549     /*
550      * Create the string if does not exist.
551      */
552     if(!st) {
553         st = (OCTET_STRING_t *)CALLOC(1, specs->struct_size);
554         *sptr = (void *)st;
555         if(!st) goto sta_failed;
556         st_allocated = 1;
557     } else {
558         st_allocated = 0;
559     }
560     if(!st->buf) {
561         /* This is separate from above section */
562         st->buf = (uint8_t *)CALLOC(1, 1);
563         if(!st->buf) {
564             if(st_allocated) {
565                 *sptr = 0;
566                 goto stb_failed;
567             } else {
568                 goto sta_failed;
569             }
570         }
571     }
572
573     /* Restore parsing context */
574     ctx = (asn_struct_ctx_t *)(((char *)*sptr) + specs->ctx_offset);
575
576     return xer_decode_general(opt_codec_ctx, ctx, *sptr, xml_tag,
577                               buf_ptr, size,
578                               opt_unexpected_tag_decoder,
579                               body_receiver);
580
581 stb_failed:
582     FREEMEM(st);
583 sta_failed:
584     rval.code = RC_FAIL;
585     rval.consumed = 0;
586     return rval;
587 }
588
589 /*
590  * Decode OCTET STRING from the hexadecimal data.
591  */
592 asn_dec_rval_t
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,
596                             size_t size) {
597     return OCTET_STRING__decode_xer(opt_codec_ctx, td, sptr, opt_mname,
598                                     buf_ptr, size, 0,
599                                     OCTET_STRING__convert_hexadecimal);
600 }
601
602 /*
603  * Decode OCTET STRING from the binary (0/1) data.
604  */
605 asn_dec_rval_t
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,
609                                size_t size) {
610     return OCTET_STRING__decode_xer(opt_codec_ctx, td, sptr, opt_mname,
611                                     buf_ptr, size, 0,
612                                     OCTET_STRING__convert_binary);
613 }
614
615 /*
616  * Decode OCTET STRING from the string (ASCII/UTF-8) data.
617  */
618 asn_dec_rval_t
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,
622                              size_t size) {
623     return OCTET_STRING__decode_xer(opt_codec_ctx, td, sptr, opt_mname,
624                                     buf_ptr, size,
625                                     OCTET_STRING__handle_control_chars,
626                                     OCTET_STRING__convert_entrefs);
627 }