2 * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
3 * Redistribution and modifications are permitted subject to BSD license.
5 #include <asn_internal.h>
6 #include <OBJECT_IDENTIFIER.h>
7 #include <OCTET_STRING.h>
8 #include <limits.h> /* for CHAR_BIT */
12 * OBJECT IDENTIFIER basic type description.
14 static ber_tlv_tag_t asn_DEF_OBJECT_IDENTIFIER_tags
[] = {
15 (ASN_TAG_CLASS_UNIVERSAL
| (6 << 2))
17 asn_TYPE_descriptor_t asn_DEF_OBJECT_IDENTIFIER
= {
20 ASN__PRIMITIVE_TYPE_free
,
21 OBJECT_IDENTIFIER_print
,
22 OBJECT_IDENTIFIER_constraint
,
25 OBJECT_IDENTIFIER_decode_xer
,
26 OBJECT_IDENTIFIER_encode_xer
,
27 OCTET_STRING_decode_uper
,
28 OCTET_STRING_encode_uper
,
29 0, /* Use generic outmost tag fetcher */
30 asn_DEF_OBJECT_IDENTIFIER_tags
,
31 sizeof(asn_DEF_OBJECT_IDENTIFIER_tags
)
32 / sizeof(asn_DEF_OBJECT_IDENTIFIER_tags
[0]),
33 asn_DEF_OBJECT_IDENTIFIER_tags
, /* Same as above */
34 sizeof(asn_DEF_OBJECT_IDENTIFIER_tags
)
35 / sizeof(asn_DEF_OBJECT_IDENTIFIER_tags
[0]),
36 0, /* No PER visible constraints */
37 0, 0, /* No members */
43 OBJECT_IDENTIFIER_constraint(asn_TYPE_descriptor_t
*td
, const void *sptr
,
44 asn_app_constraint_failed_f
*ctfailcb
, void *app_key
) {
45 const OBJECT_IDENTIFIER_t
*st
= (const OBJECT_IDENTIFIER_t
*)sptr
;
49 _ASN_CTFAIL(app_key
, td
, sptr
,
50 "%s: at least one numerical value "
52 td
->name
, __FILE__
, __LINE__
);
56 _ASN_CTFAIL(app_key
, td
, sptr
,
57 "%s: value not given (%s:%d)",
58 td
->name
, __FILE__
, __LINE__
);
67 OBJECT_IDENTIFIER_get_single_arc(uint8_t *arcbuf
, unsigned int arclen
, signed int add
, void *rvbufp
, unsigned int rvsize
) {
68 unsigned LE GCC_NOTUSED
= 1; /* Little endian (x86) */
69 uint8_t *arcend
= arcbuf
+ arclen
; /* End of arc */
70 unsigned int cache
= 0; /* No more than 14 significant bits */
71 unsigned char *rvbuf
= (unsigned char *)rvbufp
;
72 unsigned char *rvstart
= rvbuf
; /* Original start of the value buffer */
73 int inc
; /* Return value growth direction */
75 rvsize
*= CHAR_BIT
; /* bytes to bits */
76 arclen
*= 7; /* bytes to bits */
79 * The arc has the number of bits
80 * cannot be represented using supplied return value type.
83 if(arclen
> (rvsize
+ CHAR_BIT
)) {
84 errno
= ERANGE
; /* Overflow */
88 * Even if the number of bits in the arc representation
89 * is higher than the width of supplied * return value
90 * type, there is still possible to fit it when there
91 * are few unused high bits in the arc value
94 * Moreover, there is a possibility that the
95 * number could actually fit the arc space, given
96 * that add is negative, but we don't handle
97 * such "temporary lack of precision" situation here.
98 * May be considered as a bug.
100 uint8_t mask
= (0xff << (7-(arclen
- rvsize
))) & 0x7f;
101 if((*arcbuf
& mask
)) {
102 errno
= ERANGE
; /* Overflow */
105 /* Fool the routine computing unused bits */
107 cache
= *arcbuf
& 0x7f;
112 /* Faster path for common size */
113 if(rvsize
== (CHAR_BIT
* sizeof(unsigned long))) {
115 /* Gather all bits into the accumulator */
116 for(accum
= cache
; arcbuf
< arcend
; arcbuf
++)
117 accum
= (accum
<< 7) | (*arcbuf
& ~0x80);
118 if(accum
< (unsigned)-add
) {
119 errno
= ERANGE
; /* Overflow */
122 *(unsigned long *)rvbuf
= accum
+ add
; /* alignment OK! */
126 #ifndef WORDS_BIGENDIAN
127 if(*(unsigned char *)&LE
) { /* Little endian (x86) */
128 /* "Convert" to big endian */
129 rvbuf
+= rvsize
/ CHAR_BIT
- 1;
131 inc
= -1; /* Descending */
133 #endif /* !WORDS_BIGENDIAN */
134 inc
= +1; /* Big endian is known [at compile time] */
137 int bits
; /* typically no more than 3-4 bits */
139 /* Clear the high unused bits */
140 for(bits
= rvsize
- arclen
;
142 rvbuf
+= inc
, bits
-= CHAR_BIT
)
145 /* Fill the body of a value */
146 for(; arcbuf
< arcend
; arcbuf
++) {
147 cache
= (cache
<< 7) | (*arcbuf
& 0x7f);
149 if(bits
>= CHAR_BIT
) {
151 *rvbuf
= (cache
>> bits
);
162 for(rvbuf
-= inc
; rvbuf
!= rvstart
; rvbuf
-= inc
) {
163 int v
= add
+ *rvbuf
;
164 if(v
& (-1 << CHAR_BIT
)) {
165 *rvbuf
= (unsigned char)(v
+ (1 << CHAR_BIT
));
172 if(rvbuf
== rvstart
) {
173 /* No space to carry over */
174 errno
= ERANGE
; /* Overflow */
183 OBJECT_IDENTIFIER__dump_arc(uint8_t *arcbuf
, int arclen
, int add
,
184 asn_app_consume_bytes_f
*cb
, void *app_key
) {
185 char scratch
[64]; /* Conservative estimate */
186 unsigned long accum
; /* Bits accumulator */
187 char *p
; /* Position in the scratch buffer */
189 if(OBJECT_IDENTIFIER_get_single_arc(arcbuf
, arclen
, add
,
190 &accum
, sizeof(accum
)))
196 /* Fill the scratch buffer in reverse. */
197 p
= scratch
+ sizeof(scratch
);
198 for(; accum
; accum
/= 10)
199 *(--p
) = (char)(accum
% 10) + 0x30; /* Put a digit */
201 len
= sizeof(scratch
) - (p
- scratch
);
202 if(cb(p
, len
, app_key
) < 0)
207 if(cb(scratch
, 1, app_key
) < 0)
214 OBJECT_IDENTIFIER_print_arc(uint8_t *arcbuf
, int arclen
, int add
,
215 asn_app_consume_bytes_f
*cb
, void *app_key
) {
217 if(OBJECT_IDENTIFIER__dump_arc(arcbuf
, arclen
, add
, cb
, app_key
) < 0)
224 OBJECT_IDENTIFIER__dump_body(const OBJECT_IDENTIFIER_t
*st
, asn_app_consume_bytes_f
*cb
, void *app_key
) {
225 ssize_t wrote_len
= 0;
230 for(i
= 0, startn
= 0; i
< st
->size
; i
++) {
231 uint8_t b
= st
->buf
[i
];
232 if((b
& 0x80)) /* Continuation expected */
237 * First two arcs are encoded through the backdoor.
241 if(cb("2", 1, app_key
) < 0) return -1;
244 if(cb("0", 1, app_key
) < 0) return -1;
247 if(cb("1", 1, app_key
) < 0) return -1;
250 if(cb("2", 1, app_key
) < 0) return -1;
255 if(cb(".", 1, app_key
) < 0) /* Separate arcs */
258 add
= OBJECT_IDENTIFIER__dump_arc(&st
->buf
[startn
],
259 i
- startn
+ 1, add
, cb
, app_key
);
260 if(add
< 0) return -1;
261 wrote_len
+= 1 + add
;
269 static enum xer_pbd_rval
270 OBJECT_IDENTIFIER__xer_body_decode(asn_TYPE_descriptor_t
*td
, void *sptr
, const void *chunk_buf
, size_t chunk_size
) {
271 OBJECT_IDENTIFIER_t
*st
= (OBJECT_IDENTIFIER_t
*)sptr
;
272 const char *chunk_end
= (const char *)chunk_buf
+ chunk_size
;
281 arcs_count
= OBJECT_IDENTIFIER_parse_arcs(
282 (const char *)chunk_buf
, chunk_size
, arcs
,
283 sizeof(s_arcs
)/sizeof(s_arcs
[0]), &endptr
);
284 if(arcs_count
<= 0) {
285 /* Expecting more than zero arcs */
286 return XPBD_BROKEN_ENCODING
;
288 if(endptr
< chunk_end
) {
289 /* We have a tail of unrecognized data. Check its safety. */
290 if(!xer_is_whitespace(endptr
, chunk_end
- endptr
))
291 return XPBD_BROKEN_ENCODING
;
294 if((size_t)arcs_count
> sizeof(s_arcs
)/sizeof(s_arcs
[0])) {
295 arcs
= (long *)MALLOC(arcs_count
* sizeof(long));
296 if(!arcs
) return XPBD_SYSTEM_FAILURE
;
297 ret
= OBJECT_IDENTIFIER_parse_arcs(
298 (const char *)chunk_buf
, chunk_size
,
299 arcs
, arcs_count
, &endptr
);
300 if(ret
!= arcs_count
)
301 return XPBD_SYSTEM_FAILURE
; /* assert?.. */
305 * Convert arcs into BER representation.
307 ret
= OBJECT_IDENTIFIER_set_arcs(st
, arcs
, sizeof(*arcs
), arcs_count
);
308 if(arcs
!= s_arcs
) FREEMEM(arcs
);
310 return ret
? XPBD_SYSTEM_FAILURE
: XPBD_BODY_CONSUMED
;
314 OBJECT_IDENTIFIER_decode_xer(asn_codec_ctx_t
*opt_codec_ctx
,
315 asn_TYPE_descriptor_t
*td
, void **sptr
, const char *opt_mname
,
316 const void *buf_ptr
, size_t size
) {
318 return xer_decode_primitive(opt_codec_ctx
, td
,
319 sptr
, sizeof(OBJECT_IDENTIFIER_t
), opt_mname
,
320 buf_ptr
, size
, OBJECT_IDENTIFIER__xer_body_decode
);
324 OBJECT_IDENTIFIER_encode_xer(asn_TYPE_descriptor_t
*td
, void *sptr
,
325 int ilevel
, enum xer_encoder_flags_e flags
,
326 asn_app_consume_bytes_f
*cb
, void *app_key
) {
327 const OBJECT_IDENTIFIER_t
*st
= (const OBJECT_IDENTIFIER_t
*)sptr
;
336 er
.encoded
= OBJECT_IDENTIFIER__dump_body(st
, cb
, app_key
);
337 if(er
.encoded
< 0) _ASN_ENCODE_FAILED
;
343 OBJECT_IDENTIFIER_print(asn_TYPE_descriptor_t
*td
, const void *sptr
,
344 int ilevel
, asn_app_consume_bytes_f
*cb
, void *app_key
) {
345 const OBJECT_IDENTIFIER_t
*st
= (const OBJECT_IDENTIFIER_t
*)sptr
;
347 (void)td
; /* Unused argument */
348 (void)ilevel
; /* Unused argument */
351 return (cb("<absent>", 8, app_key
) < 0) ? -1 : 0;
354 if(cb("{ ", 2, app_key
) < 0)
357 if(OBJECT_IDENTIFIER__dump_body(st
, cb
, app_key
) < 0)
360 return (cb(" }", 2, app_key
) < 0) ? -1 : 0;
364 OBJECT_IDENTIFIER_get_arcs(OBJECT_IDENTIFIER_t
*oid
, void *arcs
,
365 unsigned int arc_type_size
, unsigned int arc_slots
) {
366 void *arcs_end
= (char *)arcs
+ (arc_type_size
* arc_slots
);
372 if(!oid
|| !oid
->buf
|| (arc_slots
&& arc_type_size
<= 1)) {
377 for(i
= 0; i
< oid
->size
; i
++) {
378 uint8_t b
= oid
->buf
[i
];
379 if((b
& 0x80)) /* Continuation expected */
384 * First two arcs are encoded through the backdoor.
386 unsigned LE
= 1; /* Little endian */
389 if(!arc_slots
) { num_arcs
++; continue; }
392 else if(b
<= 39) first_arc
= 0;
393 else if(b
< 79) first_arc
= 1;
396 add
= -40 * first_arc
;
397 memset(arcs
, 0, arc_type_size
);
398 *(unsigned char *)((char *)arcs
399 + ((*(char *)&LE
)?0:(arc_type_size
- 1)))
401 arcs
= ((char *)arcs
) + arc_type_size
;
404 /* Decode, if has space */
405 if(arcs
< arcs_end
) {
406 if(OBJECT_IDENTIFIER_get_single_arc(&oid
->buf
[startn
],
408 arcs
, arc_type_size
))
411 arcs
= ((char *)arcs
) + arc_type_size
;
422 * Save the single value as an object identifier arc.
425 OBJECT_IDENTIFIER_set_single_arc(uint8_t *arcbuf
, const void *arcval
, unsigned int arcval_size
, int prepared_order
) {
427 * The following conditions must hold:
429 * assert(arcval_size > 0);
430 * assert(arcval_size <= 16);
433 #ifdef WORDS_BIGENDIAN
434 const unsigned isLittleEndian
= 0;
437 unsigned isLittleEndian
= *(char *)&LE
;
439 const uint8_t *tend
, *tp
;
441 uint8_t *bp
= arcbuf
;
445 if(isLittleEndian
&& !prepared_order
) {
446 const uint8_t *a
= (const unsigned char *)arcval
+ arcval_size
- 1;
447 const uint8_t *aend
= (const uint8_t *)arcval
;
448 uint8_t *msb
= buffer
+ arcval_size
- 1;
450 for(tb
= buffer
; a
>= aend
; tb
++, a
--)
451 if((*tb
= *a
) && (tb
< msb
))
453 tend
= &buffer
[arcval_size
];
454 tp
= msb
; /* Most significant non-zero byte */
456 /* Look for most significant non-zero byte */
457 tend
= (const unsigned char *)arcval
+ arcval_size
;
458 for(tp
= (const uint8_t *)arcval
; tp
< tend
- 1; tp
++)
463 * Split the value in 7-bits chunks.
465 bits
= ((tend
- tp
) * CHAR_BIT
) % 7;
467 cache
= *tp
>> (CHAR_BIT
- bits
);
469 *bp
++ = cache
| 0x80;
471 bits
= CHAR_BIT
- bits
;
478 for(; tp
< tend
; tp
++) {
479 cache
= (cache
<< CHAR_BIT
) + *tp
;
483 *bp
++ = 0x80 | (cache
>> bits
);
486 if(bits
) *bp
++ = cache
;
487 bp
[-1] &= 0x7f; /* Clear the last bit */
493 OBJECT_IDENTIFIER_set_arcs(OBJECT_IDENTIFIER_t
*oid
, const void *arcs
, unsigned int arc_type_size
, unsigned int arc_slots
) {
496 unsigned LE
= 1; /* Little endian (x86) */
497 unsigned isLittleEndian
= *((char *)&LE
);
503 if(!oid
|| !arcs
|| arc_type_size
< 1
504 || arc_type_size
> 16
510 switch(arc_type_size
) {
512 arc0
= ((const unsigned char *)arcs
)[0];
513 arc1
= ((const unsigned char *)arcs
)[1];
516 arc0
= ((const unsigned short *)arcs
)[0];
517 arc1
= ((const unsigned short *)arcs
)[1];
520 arc0
= ((const unsigned int *)arcs
)[0];
521 arc1
= ((const unsigned int *)arcs
)[1];
525 if(isLittleEndian
) { /* Little endian (x86) */
526 const unsigned char *ps
, *pe
;
527 /* If more significant bytes are present,
528 * make them > 255 quick */
529 for(ps
= (const unsigned char *)arcs
+ 1, pe
= ps
+arc_type_size
;
531 arc0
|= *ps
, arc1
|= *(ps
+ arc_type_size
);
532 arc0
<<= CHAR_BIT
, arc1
<<= CHAR_BIT
;
533 arc0
= *((const unsigned char *)arcs
+ 0);
534 arc1
= *((const unsigned char *)arcs
+ arc_type_size
);
536 const unsigned char *ps
, *pe
;
537 /* If more significant bytes are present,
538 * make them > 255 quick */
539 for(ps
= (const unsigned char *)arcs
, pe
= ps
+arc_type_size
- 1; ps
< pe
; ps
++)
540 arc0
|= *ps
, arc1
|= *(ps
+ arc_type_size
);
541 arc0
= *((const unsigned char *)arcs
+ arc_type_size
- 1);
542 arc1
= *((const unsigned char *)arcs
+(arc_type_size
<< 1)-1);
547 * The previous chapter left us with the first and the second arcs.
548 * The values are not precise (that is, they are valid only if
549 * they're less than 255), but OK for the purposes of making
550 * the sanity test below.
554 /* 8.19.4: At most 39 subsequent values (including 0) */
558 } else if(arc0
> 2) {
559 /* 8.19.4: Only three values are allocated from the root node */
564 * After above tests it is known that the value of arc0 is completely
565 * trustworthy (0..2). However, the arc1's value is still meaningless.
569 * Roughly estimate the maximum size necessary to encode these arcs.
570 * This estimation implicitly takes in account the following facts,
571 * that cancel each other:
572 * * the first two arcs are encoded in a single value.
573 * * the first value may require more space (+1 byte)
574 * * the value of the first arc which is in range (0..2)
576 size
= ((arc_type_size
* CHAR_BIT
+ 6) / 7) * arc_slots
;
577 bp
= buf
= (uint8_t *)MALLOC(size
+ 1);
584 * Encode the first two arcs.
585 * These require special treatment.
589 uint8_t first_value
[1 + 16]; /* of two arcs */
590 uint8_t *fv
= first_value
;
593 * Simulate first_value = arc0 * 40 + arc1;
595 /* Copy the second (1'st) arcs[1] into the first_value */
597 arcs
= ((const char *)arcs
) + arc_type_size
;
599 const uint8_t *aend
= (const unsigned char *)arcs
- 1;
600 const uint8_t *a1
= (const unsigned char *)arcs
+ arc_type_size
- 1;
601 for(; a1
> aend
; fv
++, a1
--) *fv
= *a1
;
603 const uint8_t *a1
= (const uint8_t *)arcs
;
604 const uint8_t *aend
= a1
+ arc_type_size
;
605 for(; a1
< aend
; fv
++, a1
++) *fv
= *a1
;
607 /* Increase the first_value by arc0 */
608 arc0
*= 40; /* (0..80) */
609 for(tp
= first_value
+ arc_type_size
; tp
>= first_value
; tp
--) {
610 unsigned int v
= *tp
;
613 if(v
>= (1 << CHAR_BIT
)) arc0
= v
>> CHAR_BIT
;
617 assert(tp
>= first_value
);
619 bp
+= OBJECT_IDENTIFIER_set_single_arc(bp
, first_value
,
620 fv
- first_value
, 1);
624 * Save the rest of arcs.
626 for(arcs
= ((const char *)arcs
) + arc_type_size
, i
= 2;
628 i
++, arcs
= ((const char *)arcs
) + arc_type_size
) {
629 bp
+= OBJECT_IDENTIFIER_set_single_arc(bp
,
630 arcs
, arc_type_size
, 0);
633 assert((unsigned)(bp
- buf
) <= size
);
638 oid
->size
= bp
- buf
;
648 OBJECT_IDENTIFIER_parse_arcs(const char *oid_text
, ssize_t oid_txt_length
,
649 long *arcs
, unsigned int arcs_slots
, const char **opt_oid_text_end
) {
650 unsigned int arcs_count
= 0;
655 ST_WAITDIGITS
, /* Next character is expected to be a digit */
657 } state
= ST_SKIPSPACE
;
659 if(!oid_text
|| oid_txt_length
< -1 || (arcs_slots
&& !arcs
)) {
660 if(opt_oid_text_end
) *opt_oid_text_end
= oid_text
;
665 if(oid_txt_length
== -1)
666 oid_txt_length
= strlen(oid_text
);
668 for(oid_end
= oid_text
+ oid_txt_length
; oid_text
<oid_end
; oid_text
++) {
670 case 0x09: case 0x0a: case 0x0d: case 0x20: /* whitespace */
671 if(state
== ST_SKIPSPACE
) {
677 if(state
!= ST_DIGITS
678 || (oid_text
+ 1) == oid_end
) {
679 state
= ST_WAITDIGITS
;
682 if(arcs_count
< arcs_slots
)
683 arcs
[arcs_count
] = value
;
685 state
= ST_WAITDIGITS
;
687 case 0x30: case 0x31: case 0x32: case 0x33: case 0x34:
688 case 0x35: case 0x36: case 0x37: case 0x38: case 0x39:
689 if(state
!= ST_DIGITS
) {
694 long volatile new_value
= value
* 10;
695 /* GCC 4.x is being too smart without volatile */
696 if(new_value
/ 10 != value
697 || (value
= new_value
+ (*oid_text
- 0x30)) < 0) {
699 state
= ST_WAITDIGITS
;
705 /* Unexpected symbols */
706 state
= ST_WAITDIGITS
;
713 if(opt_oid_text_end
) *opt_oid_text_end
= oid_text
;
715 /* Finalize last arc */
721 if(arcs_count
< arcs_slots
)
722 arcs
[arcs_count
] = value
;