Revert, don't export asn1_find_up.
[libtasn1.git] / lib / parser_aux.c
blob5b82d273c0c1e63eef8272025c14f66e3e0ef64e
1 /*
2 * Copyright (C) 2004, 2006 Free Software Foundation
3 * Copyright (C) 2000,2001 Fabio Fiorina
5 * This file is part of LIBTASN1.
7 * The LIBTASN1 library is free software; you can redistribute it
8 * and/or modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 * 02110-1301, USA
23 #include <int.h>
24 #include <errors.h>
25 #include "parser_aux.h"
26 #include "gstr.h"
27 #include "structure.h"
28 #include "element.h"
30 char _asn1_identifierMissing[MAX_NAME_SIZE+1]; /* identifier name not found */
32 /***********************************************/
33 /* Type: list_type */
34 /* Description: type used in the list during */
35 /* the structure creation. */
36 /***********************************************/
37 typedef struct list_struct{
38 node_asn *node;
39 struct list_struct *next;
40 } list_type;
43 /* Pointer to the first element of the list */
44 list_type *firstElement=NULL;
46 /******************************************************/
47 /* Function : _asn1_add_node */
48 /* Description: creates a new NODE_ASN element and */
49 /* puts it in the list pointed by firstElement. */
50 /* Parameters: */
51 /* type: type of the new element (see TYPE_ */
52 /* and CONST_ constants). */
53 /* Return: pointer to the new element. */
54 /******************************************************/
55 node_asn *
56 _asn1_add_node(unsigned int type)
58 list_type *listElement;
59 node_asn *punt;
61 punt=(node_asn *) _asn1_malloc(sizeof(node_asn));
62 if (punt==NULL) return NULL;
64 listElement=(list_type *) _asn1_malloc(sizeof(list_type));
65 if(listElement==NULL){
66 _asn1_free(punt);
67 return NULL;
70 listElement->node=punt;
71 listElement->next=firstElement;
72 firstElement=listElement;
74 punt->left=NULL;
75 punt->name=NULL;
76 punt->type=type;
77 punt->value=NULL;
78 punt->down=NULL;
79 punt->right=NULL;
81 return punt;
84 /**
85 * asn1_find_node:
86 * @pointer: NODE_ASN element pointer.
87 * @name: null terminated string with the element's name to find.
89 * Searches for an element called NAME starting from POINTER. The
90 * name is composed by differents identifiers separated by dots. When
91 * *POINTER has a name, the first identifier must be the name of
92 * *POINTER, otherwise it must be the name of one child of *POINTER.
94 * Return value: the searching result. NULL if not found.
95 **/
96 ASN1_TYPE
97 asn1_find_node(ASN1_TYPE pointer, const char *name)
99 node_asn *p;
100 char *n_end,n[MAX_NAME_SIZE+1];
101 const char *n_start;
103 if(pointer == NULL) return NULL;
105 if(name==NULL) return NULL;
107 p=pointer;
108 n_start=name;
110 if(p->name != NULL){ /* has *pointer got a name ? */
111 n_end=strchr(n_start,'.'); /* search the first dot */
112 if(n_end){
113 memcpy(n,n_start,n_end-n_start);
114 n[n_end-n_start]=0;
115 n_start=n_end;
116 n_start++;
118 else{
119 _asn1_str_cpy(n,sizeof(n),n_start);
120 n_start=NULL;
123 while(p){
124 if((p->name) && (!strcmp(p->name,n))) break;
125 else p=p->right;
126 } /* while */
128 if(p==NULL) return NULL;
130 else{ /* *pointer doesn't have a name */
131 if(n_start[0]==0)
132 return p;
135 while(n_start){ /* Has the end of NAME been reached? */
136 n_end=strchr(n_start,'.'); /* search the next dot */
137 if(n_end){
138 memcpy(n,n_start,n_end-n_start);
139 n[n_end-n_start]=0;
140 n_start=n_end;
141 n_start++;
143 else{
144 _asn1_str_cpy(n,sizeof(n),n_start);
145 n_start=NULL;
148 if(p->down==NULL) return NULL;
150 p=p->down;
152 /* The identifier "?LAST" indicates the last element
153 in the right chain. */
154 if(!strcmp(n,"?LAST")){
155 if(p==NULL) return NULL;
156 while(p->right) p=p->right;
158 else{ /* no "?LAST" */
159 while(p){
160 if((p->name) && (!strcmp(p->name,n))) break;
161 else p=p->right;
163 if(p==NULL) return NULL;
165 } /* while */
167 return p;
171 /******************************************************************/
172 /* Function : _asn1_set_value */
173 /* Description: sets the field VALUE in a NODE_ASN element. The */
174 /* previous value (if exist) will be lost */
175 /* Parameters: */
176 /* node: element pointer. */
177 /* value: pointer to the value that you want to set. */
178 /* len: character number of value. */
179 /* Return: pointer to the NODE_ASN element. */
180 /******************************************************************/
181 node_asn *
182 _asn1_set_value(node_asn *node,const unsigned char *value,unsigned int len)
185 if(node==NULL) return node;
186 if(node->value){
187 _asn1_free(node->value);
188 node->value=NULL;
189 node->value_len = 0;
191 if(!len) return node;
192 node->value=(unsigned char *) _asn1_malloc(len);
193 if (node->value==NULL) return NULL;
194 node->value_len = len;
196 memcpy(node->value,value,len);
197 return node;
200 /******************************************************************/
201 /* Function : _asn1_set_name */
202 /* Description: sets the field NAME in a NODE_ASN element. The */
203 /* previous value (if exist) will be lost */
204 /* Parameters: */
205 /* node: element pointer. */
206 /* name: a null terminated string with the name that you want */
207 /* to set. */
208 /* Return: pointer to the NODE_ASN element. */
209 /******************************************************************/
210 node_asn *
211 _asn1_set_name(node_asn *node,const char *name)
213 if(node==NULL) return node;
215 if(node->name){
216 _asn1_free(node->name);
217 node->name=NULL;
220 if(name==NULL) return node;
222 if(strlen(name))
224 node->name=(char *) _asn1_strdup( name);
225 if (node->name==NULL) return NULL;
227 else node->name=NULL;
228 return node;
231 /******************************************************************/
232 /* Function : _asn1_set_right */
233 /* Description: sets the field RIGHT in a NODE_ASN element. */
234 /* Parameters: */
235 /* node: element pointer. */
236 /* right: pointer to a NODE_ASN element that you want be pointed*/
237 /* by NODE. */
238 /* Return: pointer to *NODE. */
239 /******************************************************************/
240 node_asn *
241 _asn1_set_right(node_asn *node,node_asn *right)
243 if(node==NULL) return node;
244 node->right=right;
245 if(right) right->left=node;
246 return node;
249 /******************************************************************/
250 /* Function : _asn1_get_right */
251 /* Description: returns the element pointed by the RIGHT field of */
252 /* a NODE_ASN element. */
253 /* Parameters: */
254 /* node: NODE_ASN element pointer. */
255 /* Return: field RIGHT of NODE. */
256 /******************************************************************/
257 node_asn *
258 _asn1_get_right(node_asn *node)
260 if(node==NULL) return NULL;
261 return node->right;
264 /******************************************************************/
265 /* Function : _asn1_get_last_right */
266 /* Description: return the last element along the right chain. */
267 /* Parameters: */
268 /* node: starting element pointer. */
269 /* Return: pointer to the last element along the right chain. */
270 /******************************************************************/
271 node_asn *
272 _asn1_get_last_right(node_asn *node)
274 node_asn *p;
276 if(node==NULL) return NULL;
277 p=node;
278 while(p->right) p=p->right;
279 return p;
282 /******************************************************************/
283 /* Function : _asn1_set_down */
284 /* Description: sets the field DOWN in a NODE_ASN element. */
285 /* Parameters: */
286 /* node: element pointer. */
287 /* down: pointer to a NODE_ASN element that you want be pointed */
288 /* by NODE. */
289 /* Return: pointer to *NODE. */
290 /******************************************************************/
291 node_asn *
292 _asn1_set_down(node_asn *node,node_asn *down)
294 if(node==NULL) return node;
295 node->down=down;
296 if(down) down->left=node;
297 return node;
300 /******************************************************************/
301 /* Function : _asn1_get_down */
302 /* Description: returns the element pointed by the DOWN field of */
303 /* a NODE_ASN element. */
304 /* Parameters: */
305 /* node: NODE_ASN element pointer. */
306 /* Return: field DOWN of NODE. */
307 /******************************************************************/
308 node_asn *
309 _asn1_get_down(node_asn *node)
311 if(node==NULL) return NULL;
312 return node->down;
315 /******************************************************************/
316 /* Function : _asn1_get_name */
317 /* Description: returns the name of a NODE_ASN element. */
318 /* Parameters: */
319 /* node: NODE_ASN element pointer. */
320 /* Return: a null terminated string. */
321 /******************************************************************/
322 char *
323 _asn1_get_name(node_asn *node)
325 if(node==NULL) return NULL;
326 return node->name;
329 /******************************************************************/
330 /* Function : _asn1_mod_type */
331 /* Description: change the field TYPE of an NODE_ASN element. */
332 /* The new value is the old one | (bitwise or) the */
333 /* paramener VALUE. */
334 /* Parameters: */
335 /* node: NODE_ASN element pointer. */
336 /* value: the integer value that must be or-ed with the current */
337 /* value of field TYPE. */
338 /* Return: NODE pointer. */
339 /******************************************************************/
340 node_asn *
341 _asn1_mod_type(node_asn *node,unsigned int value)
343 if(node==NULL) return node;
344 node->type|=value;
345 return node;
349 /******************************************************************/
350 /* Function : _asn1_remove_node */
351 /* Description: gets free the memory allocated for an NODE_ASN */
352 /* element (not the elements pointed by it). */
353 /* Parameters: */
354 /* node: NODE_ASN element pointer. */
355 /******************************************************************/
356 void
357 _asn1_remove_node(node_asn *node)
359 if(node==NULL) return;
361 if (node->name!=NULL)
362 _asn1_free(node->name);
363 if (node->value!=NULL)
364 _asn1_free(node->value);
365 _asn1_free(node);
368 /******************************************************************/
369 /* Function : __asn1_find_up */
370 /* Description: return the father of the NODE_ASN element. */
371 /* Parameters: */
372 /* node: NODE_ASN element pointer. */
373 /* Return: Null if not found. */
374 /******************************************************************/
375 node_asn *
376 __asn1_find_up(node_asn *node)
378 node_asn *p;
380 if(node==NULL) return NULL;
382 p=node;
384 while((p->left!=NULL) && (p->left->right==p)) p=p->left;
386 return p->left;
389 /******************************************************************/
390 /* Function : _asn1_delete_list */
391 /* Description: deletes the list elements (not the elements */
392 /* pointed by them). */
393 /******************************************************************/
394 void
395 _asn1_delete_list(void)
397 list_type *listElement;
399 while(firstElement){
400 listElement=firstElement;
401 firstElement=firstElement->next;
402 _asn1_free(listElement);
406 /******************************************************************/
407 /* Function : _asn1_delete_list_and nodes */
408 /* Description: deletes the list elements and the elements */
409 /* pointed by them. */
410 /******************************************************************/
411 void
412 _asn1_delete_list_and_nodes(void)
414 list_type *listElement;
416 while(firstElement){
417 listElement=firstElement;
418 firstElement=firstElement->next;
419 _asn1_remove_node(listElement->node);
420 _asn1_free(listElement);
425 char *
426 _asn1_ltostr(long v,char *str)
428 long d,r;
429 char temp[20];
430 int count,k,start;
432 if(v<0){
433 str[0]='-';
434 start=1;
435 v=-v;
437 else start=0;
439 count=0;
441 d=v/10;
442 r=v-d*10;
443 temp[start+count]='0'+(char)r;
444 count++;
445 v=d;
446 }while(v);
448 for(k=0;k<count;k++) str[k+start]=temp[start+count-k-1];
449 str[count+start]=0;
450 return str;
454 /******************************************************************/
455 /* Function : _asn1_change_integer_value */
456 /* Description: converts into DER coding the value assign to an */
457 /* INTEGER constant. */
458 /* Parameters: */
459 /* node: root of an ASN1element. */
460 /* Return: */
461 /* ASN1_ELEMENT_NOT_FOUND if NODE is NULL, */
462 /* otherwise ASN1_SUCCESS */
463 /******************************************************************/
464 asn1_retCode
465 _asn1_change_integer_value(ASN1_TYPE node)
467 node_asn *p;
468 unsigned char val[SIZEOF_UNSIGNED_LONG_INT];
469 unsigned char val2[SIZEOF_UNSIGNED_LONG_INT+1];
470 int len;
472 if(node==NULL) return ASN1_ELEMENT_NOT_FOUND;
474 p=node;
475 while(p){
476 if((type_field(p->type)==TYPE_INTEGER) && (p->type&CONST_ASSIGN)){
477 if(p->value){
478 _asn1_convert_integer(p->value,val,sizeof(val), &len);
479 asn1_octet_der(val,len,val2,&len);
480 _asn1_set_value(p,val2,len);
484 if(p->down){
485 p=p->down;
487 else{
488 if(p==node) p=NULL;
489 else if(p->right) p=p->right;
490 else{
491 while(1){
492 p=_asn1_find_up(p);
493 if(p==node){
494 p=NULL;
495 break;
497 if(p->right){
498 p=p->right;
499 break;
506 return ASN1_SUCCESS;
510 /******************************************************************/
511 /* Function : _asn1_expand_object_id */
512 /* Description: expand the IDs of an OBJECT IDENTIFIER constant. */
513 /* Parameters: */
514 /* node: root of an ASN1 element. */
515 /* Return: */
516 /* ASN1_ELEMENT_NOT_FOUND if NODE is NULL, */
517 /* otherwise ASN1_SUCCESS */
518 /******************************************************************/
519 asn1_retCode
520 _asn1_expand_object_id(ASN1_TYPE node)
522 node_asn *p,*p2,*p3,*p4,*p5;
523 char name_root[MAX_NAME_SIZE],name2[2*MAX_NAME_SIZE+1];
524 int move, tlen;
526 if(node==NULL) return ASN1_ELEMENT_NOT_FOUND;
528 _asn1_str_cpy(name_root, sizeof(name_root), node->name);
530 p=node;
531 move=DOWN;
533 while(!((p==node) && (move==UP))){
534 if(move!=UP){
535 if((type_field(p->type)==TYPE_OBJECT_ID) && (p->type&CONST_ASSIGN)){
536 p2=p->down;
537 if(p2 && (type_field(p2->type)==TYPE_CONSTANT)){
538 if(p2->value && !isdigit(p2->value[0])){
539 _asn1_str_cpy(name2, sizeof(name2), name_root);
540 _asn1_str_cat(name2, sizeof(name2), ".");
541 _asn1_str_cat(name2, sizeof(name2), p2->value);
542 p3=asn1_find_node(node,name2);
543 if(!p3 || (type_field(p3->type)!=TYPE_OBJECT_ID) ||
544 !(p3->type&CONST_ASSIGN)) return ASN1_ELEMENT_NOT_FOUND;
545 _asn1_set_down(p,p2->right);
546 _asn1_remove_node(p2);
547 p2=p;
548 p4=p3->down;
549 while(p4){
550 if(type_field(p4->type)==TYPE_CONSTANT){
551 p5=_asn1_add_node_only(TYPE_CONSTANT);
552 _asn1_set_name(p5,p4->name);
553 tlen = strlen( p4->value);
554 if (tlen > 0)
555 _asn1_set_value(p5,p4->value,tlen+1);
556 if(p2==p){
557 _asn1_set_right(p5,p->down);
558 _asn1_set_down(p,p5);
560 else{
561 _asn1_set_right(p5,p2->right);
562 _asn1_set_right(p2,p5);
564 p2=p5;
566 p4=p4->right;
568 move=DOWN;
569 continue;
573 move=DOWN;
575 else move=RIGHT;
577 if(move==DOWN){
578 if(p->down) p=p->down;
579 else move=RIGHT;
582 if(p==node) {move=UP; continue;}
584 if(move==RIGHT){
585 if(p->right) p=p->right;
586 else move=UP;
588 if(move==UP) p=_asn1_find_up(p);
592 /*******************************/
593 /* expand DEFAULT */
594 /*******************************/
595 p=node;
596 move=DOWN;
598 while(!((p==node) && (move==UP))){
599 if(move!=UP){
600 if((type_field(p->type)==TYPE_OBJECT_ID) &&
601 (p->type&CONST_DEFAULT)){
602 p2=p->down;
603 if(p2 && (type_field(p2->type)==TYPE_DEFAULT)){
604 _asn1_str_cpy(name2, sizeof(name2), name_root);
605 _asn1_str_cat(name2, sizeof(name2), ".");
606 _asn1_str_cat(name2, sizeof(name2), p2->value);
607 p3=asn1_find_node(node,name2);
608 if(!p3 || (type_field(p3->type)!=TYPE_OBJECT_ID) ||
609 !(p3->type&CONST_ASSIGN)) return ASN1_ELEMENT_NOT_FOUND;
610 p4=p3->down;
611 name2[0]=0;
612 while(p4){
613 if(type_field(p4->type)==TYPE_CONSTANT){
614 if(name2[0]) _asn1_str_cat(name2,sizeof(name2),".");
615 _asn1_str_cat(name2,sizeof(name2),p4->value);
617 p4=p4->right;
619 tlen = strlen(name2);
620 if (tlen > 0)
621 _asn1_set_value(p2,name2,tlen+1);
624 move=DOWN;
626 else move=RIGHT;
628 if(move==DOWN){
629 if(p->down) p=p->down;
630 else move=RIGHT;
633 if(p==node) {move=UP; continue;}
635 if(move==RIGHT){
636 if(p->right) p=p->right;
637 else move=UP;
639 if(move==UP) p=_asn1_find_up(p);
642 return ASN1_SUCCESS;
646 /******************************************************************/
647 /* Function : _asn1_type_set_config */
648 /* Description: sets the CONST_SET and CONST_NOT_USED properties */
649 /* in the fields of the SET elements. */
650 /* Parameters: */
651 /* node: root of an ASN1 element. */
652 /* Return: */
653 /* ASN1_ELEMENT_NOT_FOUND if NODE is NULL, */
654 /* otherwise ASN1_SUCCESS */
655 /******************************************************************/
656 asn1_retCode
657 _asn1_type_set_config(ASN1_TYPE node)
659 node_asn *p,*p2;
660 int move;
662 if(node==NULL) return ASN1_ELEMENT_NOT_FOUND;
664 p=node;
665 move=DOWN;
667 while(!((p==node) && (move==UP))){
668 if(move!=UP){
669 if(type_field(p->type)==TYPE_SET){
670 p2=p->down;
671 while(p2){
672 if(type_field(p2->type)!=TYPE_TAG)
673 p2->type|=CONST_SET|CONST_NOT_USED;
674 p2=p2->right;
677 move=DOWN;
679 else move=RIGHT;
681 if(move==DOWN){
682 if(p->down) p=p->down;
683 else move=RIGHT;
686 if(p==node) {move=UP; continue;}
688 if(move==RIGHT){
689 if(p->right) p=p->right;
690 else move=UP;
692 if(move==UP) p=_asn1_find_up(p);
695 return ASN1_SUCCESS;
699 /******************************************************************/
700 /* Function : _asn1_check_identifier */
701 /* Description: checks the definitions of all the identifiers */
702 /* and the first element of an OBJECT_ID (e.g. {pkix 0 4}). */
703 /* The _asn1_identifierMissing global variable is filled if */
704 /* necessary. */
705 /* Parameters: */
706 /* node: root of an ASN1 element. */
707 /* Return: */
708 /* ASN1_ELEMENT_NOT_FOUND if NODE is NULL, */
709 /* ASN1_IDENTIFIER_NOT_FOUND if an identifier is not defined, */
710 /* otherwise ASN1_SUCCESS */
711 /******************************************************************/
712 asn1_retCode
713 _asn1_check_identifier(ASN1_TYPE node)
715 node_asn *p,*p2;
716 char name2[MAX_NAME_SIZE*2+2];
718 if(node==NULL) return ASN1_ELEMENT_NOT_FOUND;
720 p=node;
721 while(p){
722 if(type_field(p->type)==TYPE_IDENTIFIER){
723 _asn1_str_cpy(name2, sizeof(name2), node->name);
724 _asn1_str_cat(name2, sizeof(name2), ".");
725 _asn1_str_cat(name2, sizeof(name2), p->value);
726 p2=asn1_find_node(node,name2);
727 if(p2==NULL){
728 strcpy(_asn1_identifierMissing,p->value);
729 return ASN1_IDENTIFIER_NOT_FOUND;
732 else if((type_field(p->type)==TYPE_OBJECT_ID) &&
733 (p->type&CONST_DEFAULT)){
734 p2=p->down;
735 if(p2 && (type_field(p2->type)==TYPE_DEFAULT)){
736 _asn1_str_cpy(name2, sizeof(name2), node->name);
737 _asn1_str_cat(name2, sizeof(name2), ".");
738 _asn1_str_cat(name2, sizeof(name2), p2->value);
739 strcpy(_asn1_identifierMissing,p2->value);
740 p2=asn1_find_node(node,name2);
741 if(!p2 || (type_field(p2->type)!=TYPE_OBJECT_ID) ||
742 !(p2->type&CONST_ASSIGN))
743 return ASN1_IDENTIFIER_NOT_FOUND;
744 else
745 _asn1_identifierMissing[0]=0;
748 else if((type_field(p->type)==TYPE_OBJECT_ID) &&
749 (p->type&CONST_ASSIGN)){
750 p2=p->down;
751 if(p2 && (type_field(p2->type)==TYPE_CONSTANT)){
752 if(p2->value && !isdigit(p2->value[0])){
753 _asn1_str_cpy(name2, sizeof(name2), node->name);
754 _asn1_str_cat(name2, sizeof(name2), ".");
755 _asn1_str_cat(name2, sizeof(name2), p2->value);
756 strcpy(_asn1_identifierMissing,p2->value);
757 p2=asn1_find_node(node,name2);
758 if(!p2 || (type_field(p2->type)!=TYPE_OBJECT_ID) ||
759 !(p2->type&CONST_ASSIGN))
760 return ASN1_IDENTIFIER_NOT_FOUND;
761 else
762 _asn1_identifierMissing[0]=0;
767 if(p->down){
768 p=p->down;
770 else if(p->right) p=p->right;
771 else{
772 while(1){
773 p=_asn1_find_up(p);
774 if(p==node){
775 p=NULL;
776 break;
778 if(p->right){
779 p=p->right;
780 break;
786 return ASN1_SUCCESS;
790 /******************************************************************/
791 /* Function : _asn1_set_default_tag */
792 /* Description: sets the default IMPLICIT or EXPLICIT property in */
793 /* the tagged elements that don't have this declaration. */
794 /* Parameters: */
795 /* node: pointer to a DEFINITIONS element. */
796 /* Return: */
797 /* ASN1_ELEMENT_NOT_FOUND if NODE is NULL or not a pointer to */
798 /* a DEFINITIONS element, */
799 /* otherwise ASN1_SUCCESS */
800 /******************************************************************/
801 asn1_retCode
802 _asn1_set_default_tag(ASN1_TYPE node)
804 node_asn *p;
806 if((node==NULL) || (type_field(node->type)!=TYPE_DEFINITIONS))
807 return ASN1_ELEMENT_NOT_FOUND;
809 p=node;
810 while(p){
811 if((type_field(p->type)==TYPE_TAG) &&
812 !(p->type&CONST_EXPLICIT) &&
813 !(p->type&CONST_IMPLICIT)){
814 if(node->type&CONST_EXPLICIT) p->type|=CONST_EXPLICIT;
815 else p->type|=CONST_IMPLICIT;
818 if(p->down){
819 p=p->down;
821 else if(p->right) p=p->right;
822 else{
823 while(1){
824 p=_asn1_find_up(p);
825 if(p==node){
826 p=NULL;
827 break;
829 if(p->right){
830 p=p->right;
831 break;
837 return ASN1_SUCCESS;
842 static const char*
843 parse_version_number( const char *s, int *number )
845 int val = 0;
847 if( *s == '0' && isdigit(s[1]) )
848 return NULL; /* leading zeros are not allowed */
849 for ( ; isdigit(*s); s++ ) {
850 val *= 10;
851 val += *s - '0';
853 *number = val;
854 return val < 0? NULL : s;
857 /* The parse version functions were copied from libgcrypt.
859 static const char *
860 parse_version_string( const char *s, int *major, int *minor, int *micro )
862 s = parse_version_number( s, major );
863 if( !s || *s != '.' )
864 return NULL;
865 s++;
866 s = parse_version_number( s, minor );
867 if( !s || *s != '.' )
868 return NULL;
869 s++;
870 s = parse_version_number( s, micro );
871 if( !s )
872 return NULL;
873 return s; /* patchlevel */
877 * asn1_check_version - check for library version
878 * @req_version: Required version number, or NULL.
880 * Check that the the version of the library is at minimum the
881 * requested one and return the version string; return %NULL if the
882 * condition is not satisfied. If a %NULL is passed to this function,
883 * no check is done, but the version string is simply returned.
885 * See %LIBTASN1_VERSION for a suitable @req_version string.
887 * Return value: Version string of run-time library, or %NULL if the
888 * run-time library does not meet the required version number.
890 const char *
891 asn1_check_version( const char *req_version )
893 const char *ver = LIBTASN1_VERSION;
894 int my_major, my_minor, my_micro;
895 int rq_major, rq_minor, rq_micro;
896 const char *my_plvl, *rq_plvl;
898 if ( !req_version )
899 return ver;
901 my_plvl = parse_version_string( ver, &my_major, &my_minor, &my_micro );
902 if ( !my_plvl )
903 return NULL; /* very strange our own version is bogus */
904 rq_plvl = parse_version_string( req_version, &rq_major, &rq_minor,
905 &rq_micro );
906 if ( !rq_plvl )
907 return NULL; /* req version string is invalid */
909 if ( my_major > rq_major
910 || (my_major == rq_major && my_minor > rq_minor)
911 || (my_major == rq_major && my_minor == rq_minor
912 && my_micro > rq_micro)
913 || (my_major == rq_major && my_minor == rq_minor
914 && my_micro == rq_micro
915 && strcmp( my_plvl, rq_plvl ) >= 0) ) {
916 return ver;
918 return NULL;