optimized _asn1_find_up().
[platform/upstream/libtasn1.git] / lib / element.c
index 36f9248..c2b7107 100644 (file)
@@ -1,21 +1,22 @@
 /*
- *      Copyright (C) 2000,2001,2002,2003 Fabio Fiorina
+ * Copyright (C) 2000-2014 Free Software Foundation, Inc.
  *
- * This file is part of LIBASN1.
+ * This file is part of LIBTASN1.
  *
- * The LIBTASN1 library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public   
- * License as published by the Free Software Foundation; either 
+ * The LIBTASN1 library is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
  */
 
 /*****************************************************/
 
 
 #include <int.h>
-#include <errors.h>
 #include "parser_aux.h"
-#include "der.h"
 #include <gstr.h>
 #include "structure.h"
 
+#include "element.h"
+
 void
-_asn1_hierarchical_name(node_asn *node,char *name,int name_size)
+_asn1_hierarchical_name (asn1_node node, char *name, int name_size)
 {
-  node_asn *p;
+  asn1_node p;
   char tmp_name[64];
 
-  p=node;
-
-  name[0]=0;
+  p = node;
 
-  while(p != NULL){
-    if(p->name != NULL){
-      _asn1_str_cpy(tmp_name,sizeof(tmp_name),name),
+  name[0] = 0;
 
-      _asn1_str_cpy(name,name_size,p->name);
-      _asn1_str_cat(name,name_size,".");
-      _asn1_str_cat(name,name_size,tmp_name);
+  while (p != NULL)
+    {
+      if (p->name[0] != 0)
+       {
+         _asn1_str_cpy (tmp_name, sizeof (tmp_name), name),
+           _asn1_str_cpy (name, name_size, p->name);
+         _asn1_str_cat (name, name_size, ".");
+         _asn1_str_cat (name, name_size, tmp_name);
+       }
+      p = _asn1_get_up (p);
     }
-    p=_asn1_find_up(p);
-  }
 
-  if(name[0]==0) _asn1_str_cpy(name,name_size,"ROOT");
+  if (name[0] == 0)
+    _asn1_str_cpy (name, name_size, "ROOT");
 }
 
 
@@ -71,76 +74,90 @@ _asn1_hierarchical_name(node_asn *node,char *name,int name_size)
 /*   len: number of significant byte of value_out.                */
 /* Return: ASN1_MEM_ERROR or ASN1_SUCCESS                         */
 /******************************************************************/
-asn1_retCode
-_asn1_convert_integer(const char *value,unsigned char *value_out,int value_out_size, int *len)
+int
+_asn1_convert_integer (const unsigned char *value, unsigned char *value_out,
+                      int value_out_size, int *len)
 {
   char negative;
   unsigned char val[SIZEOF_UNSIGNED_LONG_INT];
   long valtmp;
-  int k,k2;
+  int k, k2;
 
-  valtmp=strtol(value,NULL,10);
-  
-  for(k=0;k<SIZEOF_UNSIGNED_LONG_INT;k++){
-    val[SIZEOF_UNSIGNED_LONG_INT-k-1]=(valtmp >> (8*k)) & 0xFF;
-  }
+  valtmp = _asn1_strtol (value, NULL, 10);
 
-  if(val[0]&0x80) negative=1;
-  else negative=0;
+  for (k = 0; k < SIZEOF_UNSIGNED_LONG_INT; k++)
+    {
+      val[SIZEOF_UNSIGNED_LONG_INT - k - 1] = (valtmp >> (8 * k)) & 0xFF;
+    }
 
-  for(k=0;k<SIZEOF_UNSIGNED_LONG_INT-1;k++){
-    if(negative && (val[k]!=0xFF)) break;
-    else if(!negative && val[k]) break;
-  }
-       
-  if((negative && !(val[k]&0x80)) ||
-     (!negative && (val[k]&0x80))) k--; 
+  if (val[0] & 0x80)
+    negative = 1;
+  else
+    negative = 0;
 
-  *len=SIZEOF_UNSIGNED_LONG_INT-k;  
+  for (k = 0; k < SIZEOF_UNSIGNED_LONG_INT - 1; k++)
+    {
+      if (negative && (val[k] != 0xFF))
+       break;
+      else if (!negative && val[k])
+       break;
+    }
 
-  if (SIZEOF_UNSIGNED_LONG_INT-k> value_out_size)
-    /* VALUE_OUT is too short to contain the value convertion */
-    return ASN1_MEM_ERROR;
+  if ((negative && !(val[k] & 0x80)) || (!negative && (val[k] & 0x80)))
+    k--;
 
-  for(k2=k;k2<SIZEOF_UNSIGNED_LONG_INT;k2++)
-    value_out[k2-k]=val[k2];
+  *len = SIZEOF_UNSIGNED_LONG_INT - k;
 
+  if (SIZEOF_UNSIGNED_LONG_INT - k > value_out_size)
+    /* VALUE_OUT is too short to contain the value conversion */
+    return ASN1_MEM_ERROR;
 
-#ifdef LIBTASN1_DEBUG_INTEGER
-  _libtasn1_log("_asn1_convert_integer: valueIn=%s, lenOut=%d",value,*len);
-  for(k=0;k<SIZEOF_UNSIGNED_LONG_INT;k++)
-    _libtasn1_log(", vOut[%d]=%d",k,value_out[k]);
-  _libtasn1_log("\n");
-#endif
+  if (value_out != NULL)
+    {
+      for (k2 = k; k2 < SIZEOF_UNSIGNED_LONG_INT; k2++)
+        value_out[k2 - k] = val[k2];
+    }
 
+#if 0
+  printf ("_asn1_convert_integer: valueIn=%s, lenOut=%d", value, *len);
+  for (k = 0; k < SIZEOF_UNSIGNED_LONG_INT; k++)
+    printf (", vOut[%d]=%d", k, value_out[k]);
+  printf ("\n");
+#endif
 
   return ASN1_SUCCESS;
 }
 
 
-int 
-_asn1_append_sequence_set(node_asn *node)
+int
+_asn1_append_sequence_set (asn1_node node)
 {
-  node_asn *p,*p2;
-  char temp[10];
+  asn1_node p, p2;
+  char temp[LTOSTR_MAX_SIZE];
   long n;
 
-  if(!node || !(node->down)) return ASN1_GENERIC_ERROR;
-
-  p=node->down;
-  while((type_field(p->type)==TYPE_TAG) || (type_field(p->type)==TYPE_SIZE)) p=p->right;
-  p2=_asn1_copy_structure3(p);
-  while(p->right) p=p->right;
-  _asn1_set_right(p,p2);
-  
-  if(p->name==NULL) _asn1_str_cpy(temp,sizeof(temp),"?1");
-  else{
-    n=strtol(p->name+1,NULL,0);
-    n++;
-    temp[0]='?';
-    _asn1_ltostr(n,temp+1);
-  } 
-  _asn1_set_name(p2,temp);
+  if (!node || !(node->down))
+    return ASN1_GENERIC_ERROR;
+
+  p = node->down;
+  while ((type_field (p->type) == ASN1_ETYPE_TAG)
+        || (type_field (p->type) == ASN1_ETYPE_SIZE))
+    p = p->right;
+  p2 = _asn1_copy_structure3 (p);
+  while (p->right)
+    p = p->right;
+  _asn1_set_right (p, p2);
+
+  if (p->name[0] == 0)
+    _asn1_str_cpy (temp, sizeof (temp), "?1");
+  else
+    {
+      n = strtol (p->name + 1, NULL, 0);
+      n++;
+      temp[0] = '?';
+      _asn1_ltostr (n, temp + 1);
+    }
+  _asn1_set_name (p2, temp);
   /*  p2->type |= CONST_OPTION; */
 
   return ASN1_SUCCESS;
@@ -148,357 +165,455 @@ _asn1_append_sequence_set(node_asn *node)
 
 
 /**
-  * asn1_write_value - Set the value of one element inside a structure.
-  * @node_root: pointer to a structure
-  * @name: the name of the element inside the structure that you want to set.
-  * @ivalue: vector used to specify the value to set. If len is >0, 
-  * VALUE must be a two's complement form integer.
-  * if len=0 *VALUE must be a null terminated string with an integer value. 
-  * @len: number of bytes of *value to use to set the value: value[0]..value[len-1]
-  *  or 0 if value is a null terminated string
-  * Description:
-  *
-  * Set the value of one element inside a structure.
-  * 
-  * Returns:
-  * 
-  *   ASN1_SUCCESS\: set value OK
-  *
-  *   ASN1_ELEMENT_NOT_FOUND\: NAME is not a valid element.
-  *
-  *   ASN1_VALUE_NOT_VALID\: VALUE has a wrong format.
-  * 
-  * Examples:  
-  *   description for each type
-  *
-  *\begin{itemize}
-  * \item INTEGER\: VALUE must contain a two's complement form integer.
-  *            value[0]=0xFF ,               len=1 -> integer=-1
-  *            value[0]=0xFF value[1]=0xFF , len=2 -> integer=-1
-  *            value[0]=0x01 ,               len=1 -> integer= 1
-  *            value[0]=0x00 value[1]=0x01 , len=2 -> integer= 1
-  *            value="123"                 , len=0 -> integer= 123
-  *
-  * \item ENUMERATED\: as INTEGER (but only with not negative numbers)
-  *
-  * \item BOOLEAN\: VALUE must be the null terminated string "TRUE" or "FALSE" and LEN != 0
-  *            value="TRUE" , len=1 -> boolean=TRUE
-  *            value="FALSE" , len=1 -> boolean=FALSE
-  *
-  * \item OBJECT IDENTIFIER\: VALUE must be a null terminated string with each number separated by
-  *                      a dot (e.g. "1.2.3.543.1"). 
-  *                      LEN != 0
-  *            value="1 2 840 10040 4 3" , len=1 -> OID=dsa-with-sha
-  *
-  * \item UTCTime\: VALUE must be a null terminated string in one of these formats\:
-  *            "YYMMDDhhmmssZ" "YYMMDDhhmmssZ" "YYMMDDhhmmss+hh'mm'" "YYMMDDhhmmss-hh'mm'"
-  *            "YYMMDDhhmm+hh'mm'" "YYMMDDhhmm-hh'mm'".  
-  *            LEN != 0
-  *            value="9801011200Z" , len=1 -> time=Jannuary 1st, 1998 at 12h 00m  Greenwich Mean Time
-  *
-  * \item GeneralizedTime\: VALUE must be in one of this format\:
-  *                    "YYYYMMDDhhmmss.sZ" "YYYYMMDDhhmmss.sZ" "YYYYMMDDhhmmss.s+hh'mm'" 
-  *                    "YYYYMMDDhhmmss.s-hh'mm'" "YYYYMMDDhhmm+hh'mm'" "YYYYMMDDhhmm-hh'mm'" 
-  *                    where ss.s indicates the seconds with any precision like "10.1" or "01.02".
-  *                    LEN != 0
-  *            value="2001010112001.12-0700" , len=1 -> time=Jannuary 1st, 2001 at 12h 00m 01.12s 
-  *                                                     Pacific Daylight Time
-  *
-  * \item OCTET STRING\: VALUE contains the octet string and LEN is the number of octet.
-  *            value="$\backslash$x01$\backslash$x02$\backslash$x03" , len=3  -> three bytes octet string
-  *
-  * \item GeneralString\: VALUE contains the generalstring and LEN is the number of octet.
-  *            value="$\backslash$x01$\backslash$x02$\backslash$x03" , len=3  -> three bytes generalstring
-  *
-  * \item BIT STRING\: VALUE contains the bit string organized by bytes and LEN is the number of bits.
-  *            value="$\backslash$xCF" , len=6 -> bit string="110011" (six bits)
-  *
-  * \item CHOICE\: if NAME indicates a choice type, VALUE must specify one of the alternatives with a
-  *           null terminated string. LEN != 0
-  *           Using "pkix.asn"\:
-  *           result=asn1_write_value(cert,"certificate1.tbsCertificate.subject","rdnSequence",1);
-  *
-  * \item ANY\: VALUE indicates the der encoding of a structure.
-  *        LEN != 0 
-  *
-  * \item SEQUENCE OF\: VALUE must be the null terminated string "NEW" and LEN != 0. With this 
-  *                instruction another element is appended in the sequence. The name of this
-  *                element will be "?1" if it's the first one, "?2" for the second and so on.
-  *
-  *           Using "pkix.asn"\:   
-  *
-  *           result=asn1_write_value(cert,"certificate1.tbsCertificate.subject.rdnSequence","NEW",1);
-  *
-  * \item SET OF\: the same as SEQUENCE OF. 
-  *           Using "pkix.asn":
-  *
-  *           result=asn1_write_value(cert,"tbsCertificate.subject.rdnSequence.?LAST","NEW",1);
-  *\end{itemize}
-  *
-  * If an element is OPTIONAL and you want to delete it, you must use the value=NULL and len=0.
-  *
-  *           Using "pkix.asn"\:
-  *
-  *           result=asn1_write_value(cert,"tbsCertificate.issuerUniqueID",NULL,0);
-  * 
-  **/
-asn1_retCode 
-asn1_write_value(node_asn *node_root,const char *name,
-                const void *ivalue,int len)
+ * asn1_write_value:
+ * @node_root: pointer to a structure
+ * @name: the name of the element inside the structure that you want to set.
+ * @ivalue: vector used to specify the value to set. If len is >0,
+ *   VALUE must be a two's complement form integer.  if len=0 *VALUE
+ *   must be a null terminated string with an integer value.
+ * @len: number of bytes of *value to use to set the value:
+ *   value[0]..value[len-1] or 0 if value is a null terminated string
+ *
+ * Set the value of one element inside a structure.
+ *
+ * If an element is OPTIONAL and you want to delete it, you must use
+ * the value=NULL and len=0.  Using "pkix.asn":
+ *
+ * result=asn1_write_value(cert, "tbsCertificate.issuerUniqueID",
+ * NULL, 0);
+ *
+ * Description for each type:
+ *
+ * INTEGER: VALUE must contain a two's complement form integer.
+ *
+ *            value[0]=0xFF ,               len=1 -> integer=-1.
+ *            value[0]=0xFF value[1]=0xFF , len=2 -> integer=-1.
+ *            value[0]=0x01 ,               len=1 -> integer= 1.
+ *            value[0]=0x00 value[1]=0x01 , len=2 -> integer= 1.
+ *            value="123"                 , len=0 -> integer= 123.
+ *
+ * ENUMERATED: As INTEGER (but only with not negative numbers).
+ *
+ * BOOLEAN: VALUE must be the null terminated string "TRUE" or
+ *   "FALSE" and LEN != 0.
+ *
+ *            value="TRUE" , len=1 -> boolean=TRUE.
+ *            value="FALSE" , len=1 -> boolean=FALSE.
+ *
+ * OBJECT IDENTIFIER: VALUE must be a null terminated string with
+ *   each number separated by a dot (e.g. "1.2.3.543.1").  LEN != 0.
+ *
+ *            value="1 2 840 10040 4 3" , len=1 -> OID=dsa-with-sha.
+ *
+ * UTCTime: VALUE must be a null terminated string in one of these
+ *   formats: "YYMMDDhhmmssZ", "YYMMDDhhmmssZ",
+ *   "YYMMDDhhmmss+hh'mm'", "YYMMDDhhmmss-hh'mm'",
+ *   "YYMMDDhhmm+hh'mm'", or "YYMMDDhhmm-hh'mm'".  LEN != 0.
+ *
+ *            value="9801011200Z" , len=1 -> time=Jannuary 1st, 1998
+ *            at 12h 00m Greenwich Mean Time
+ *
+ * GeneralizedTime: VALUE must be in one of this format:
+ *   "YYYYMMDDhhmmss.sZ", "YYYYMMDDhhmmss.sZ",
+ *   "YYYYMMDDhhmmss.s+hh'mm'", "YYYYMMDDhhmmss.s-hh'mm'",
+ *   "YYYYMMDDhhmm+hh'mm'", or "YYYYMMDDhhmm-hh'mm'" where ss.s
+ *   indicates the seconds with any precision like "10.1" or "01.02".
+ *   LEN != 0
+ *
+ *            value="2001010112001.12-0700" , len=1 -> time=Jannuary
+ *            1st, 2001 at 12h 00m 01.12s Pacific Daylight Time
+ *
+ * OCTET STRING: VALUE contains the octet string and LEN is the
+ *   number of octets.
+ *
+ *            value="$\backslash$x01$\backslash$x02$\backslash$x03" ,
+ *            len=3 -> three bytes octet string
+ *
+ * GeneralString: VALUE contains the generalstring and LEN is the
+ *   number of octets.
+ *
+ *            value="$\backslash$x01$\backslash$x02$\backslash$x03" ,
+ *            len=3 -> three bytes generalstring
+ *
+ * BIT STRING: VALUE contains the bit string organized by bytes and
+ *   LEN is the number of bits.
+ *
+ *   value="$\backslash$xCF" , len=6 -> bit string="110011" (six
+ *   bits)
+ *
+ * CHOICE: if NAME indicates a choice type, VALUE must specify one of
+ *   the alternatives with a null terminated string. LEN != 0. Using
+ *   "pkix.asn"\:
+ *
+ *           result=asn1_write_value(cert,
+ *           "certificate1.tbsCertificate.subject", "rdnSequence",
+ *           1);
+ *
+ * ANY: VALUE indicates the der encoding of a structure.  LEN != 0.
+ *
+ * SEQUENCE OF: VALUE must be the null terminated string "NEW" and
+ *   LEN != 0. With this instruction another element is appended in
+ *   the sequence. The name of this element will be "?1" if it's the
+ *   first one, "?2" for the second and so on.
+ *
+ *   Using "pkix.asn"\:
+ *
+ *   result=asn1_write_value(cert,
+ *   "certificate1.tbsCertificate.subject.rdnSequence", "NEW", 1);
+ *
+ * SET OF: the same as SEQUENCE OF.  Using "pkix.asn":
+ *
+ *           result=asn1_write_value(cert,
+ *           "tbsCertificate.subject.rdnSequence.?LAST", "NEW", 1);
+ *
+ * Returns: %ASN1_SUCCESS if the value was set,
+ *   %ASN1_ELEMENT_NOT_FOUND if @name is not a valid element, and
+ *   %ASN1_VALUE_NOT_VALID if @ivalue has a wrong format.
+ **/
+int
+asn1_write_value (asn1_node node_root, const char *name,
+                 const void *ivalue, int len)
 {
-  node_asn *node,*p,*p2;
-  unsigned char *temp,*value_temp=NULL,*default_temp=NULL;
-  int len2,k,k2,negative;
-  const unsigned char* value = ivalue;
-
-  node=_asn1_find_node(node_root,name);
-  if(node==NULL) return  ASN1_ELEMENT_NOT_FOUND;
-
-  if((node->type & CONST_OPTION) && (value==NULL) && (len==0)){
-    asn1_delete_structure(&node);
-    return ASN1_SUCCESS;
-  }
-
-  if((type_field(node->type) == TYPE_SEQUENCE_OF) && (value == NULL) && (len==0)){
-    p=node->down;
-    while((type_field(p->type)==TYPE_TAG) || (type_field(p->type)==TYPE_SIZE)) p=p->right;
-
-    while(p->right)
-      asn1_delete_structure(&p->right);
-
-    return ASN1_SUCCESS;
-  }
-
-  switch(type_field(node->type)){
-  case TYPE_BOOLEAN:
-    if(!strcmp(value,"TRUE")){
-      if(node->type&CONST_DEFAULT){
-       p=node->down;
-       while(type_field(p->type)!=TYPE_DEFAULT) p=p->right;
-       if(p->type&CONST_TRUE) _asn1_set_value(node,NULL,0);
-       else _asn1_set_value(node,"T",1);
-      }
-      else _asn1_set_value(node,"T",1);
-    }
-    else if(!strcmp(value,"FALSE")){
-      if(node->type&CONST_DEFAULT){
-       p=node->down;
-       while(type_field(p->type)!=TYPE_DEFAULT) p=p->right;
-       if(p->type&CONST_FALSE) _asn1_set_value(node,NULL,0);
-       else _asn1_set_value(node,"F",1);
-      }
-      else _asn1_set_value(node,"F",1);
-    }
-    else return ASN1_VALUE_NOT_VALID;
-    break;
-  case TYPE_INTEGER: case TYPE_ENUMERATED:
-    if(len==0){
-      if((isdigit(value[0])) || (value[0]=='-')){
-       value_temp=(unsigned char *)_asn1_alloca(SIZEOF_UNSIGNED_LONG_INT);
-       if (value_temp==NULL) return ASN1_MEM_ALLOC_ERROR;
-
-       _asn1_convert_integer(value,value_temp,SIZEOF_UNSIGNED_LONG_INT, &len);
-      }
-      else{ /* is an identifier like v1 */
-       if(!(node->type&CONST_LIST)) return ASN1_VALUE_NOT_VALID;
-       p=node->down;
-       while(p){
-         if(type_field(p->type)==TYPE_CONSTANT){
-           if((p->name) && (!strcmp(p->name,value))){
-             value_temp=(unsigned char *)_asn1_alloca(SIZEOF_UNSIGNED_LONG_INT);
-             if (value_temp==NULL) return ASN1_MEM_ALLOC_ERROR;
-
-             _asn1_convert_integer(p->value,value_temp,SIZEOF_UNSIGNED_LONG_INT, &len);
-             break;
-           }
-         }
-         p=p->right;
-       }
-       if(p==NULL) return ASN1_VALUE_NOT_VALID;
-      }
-    }
-    else{ /* len != 0 */
-      value_temp=(unsigned char *)_asn1_alloca(len);
-      if (value_temp==NULL) return ASN1_MEM_ALLOC_ERROR;
-      memcpy(value_temp,value,len);
+  asn1_node node, p, p2;
+  unsigned char *temp, *value_temp = NULL, *default_temp = NULL;
+  int len2, k, k2, negative;
+  size_t i;
+  const unsigned char *value = ivalue;
+  unsigned int type;
+
+  node = asn1_find_node (node_root, name);
+  if (node == NULL)
+    return ASN1_ELEMENT_NOT_FOUND;
+
+  if ((node->type & CONST_OPTION) && (value == NULL) && (len == 0))
+    {
+      asn1_delete_structure (&node);
+      return ASN1_SUCCESS;
     }
 
+  type = type_field (node->type);
 
-    if(value_temp[0]&0x80) negative=1;
-    else negative=0;
+  if ((type == ASN1_ETYPE_SEQUENCE_OF || type == ASN1_ETYPE_SET_OF) && (value == NULL) && (len == 0))
+    {
+      p = node->down;
+      while ((type_field (p->type) == ASN1_ETYPE_TAG)
+            || (type_field (p->type) == ASN1_ETYPE_SIZE))
+       p = p->right;
 
-    if(negative && (type_field(node->type)==TYPE_ENUMERATED)) 
-      {_asn1_afree(value_temp);return ASN1_VALUE_NOT_VALID;}
+      while (p->right)
+       asn1_delete_structure (&p->right);
 
-    for(k=0;k<len-1;k++)
-      if(negative && (value_temp[k]!=0xFF)) break;
-      else if(!negative && value_temp[k]) break;
+      return ASN1_SUCCESS;
+    }
 
-    if((negative && !(value_temp[k]&0x80)) ||
-       (!negative && (value_temp[k]&0x80))) k--; 
+  /* Don't allow element deletion for other types */
+  if (value == NULL)
+    {
+      return ASN1_VALUE_NOT_VALID;
+    }
 
-    _asn1_length_der(len-k,NULL,&len2);
-    temp=(unsigned char *)_asn1_alloca(len-k+len2);
-    if (temp==NULL) return ASN1_MEM_ALLOC_ERROR;
+  switch (type)
+    {
+    case ASN1_ETYPE_BOOLEAN:
+      if (!_asn1_strcmp (value, "TRUE"))
+       {
+         if (node->type & CONST_DEFAULT)
+           {
+             p = node->down;
+             while (type_field (p->type) != ASN1_ETYPE_DEFAULT)
+               p = p->right;
+             if (p->type & CONST_TRUE)
+               _asn1_set_value (node, NULL, 0);
+             else
+               _asn1_set_value (node, "T", 1);
+           }
+         else
+           _asn1_set_value (node, "T", 1);
+       }
+      else if (!_asn1_strcmp (value, "FALSE"))
+       {
+         if (node->type & CONST_DEFAULT)
+           {
+             p = node->down;
+             while (type_field (p->type) != ASN1_ETYPE_DEFAULT)
+               p = p->right;
+             if (p->type & CONST_FALSE)
+               _asn1_set_value (node, NULL, 0);
+             else
+               _asn1_set_value (node, "F", 1);
+           }
+         else
+           _asn1_set_value (node, "F", 1);
+       }
+      else
+       return ASN1_VALUE_NOT_VALID;
+      break;
+    case ASN1_ETYPE_INTEGER:
+    case ASN1_ETYPE_ENUMERATED:
+      if (len == 0)
+       {
+         if ((isdigit (value[0])) || (value[0] == '-'))
+           {
+             value_temp = malloc (SIZEOF_UNSIGNED_LONG_INT);
+             if (value_temp == NULL)
+               return ASN1_MEM_ALLOC_ERROR;
+
+             _asn1_convert_integer (value, value_temp,
+                                    SIZEOF_UNSIGNED_LONG_INT, &len);
+           }
+         else
+           {                   /* is an identifier like v1 */
+             if (!(node->type & CONST_LIST))
+               return ASN1_VALUE_NOT_VALID;
+             p = node->down;
+             while (p)
+               {
+                 if (type_field (p->type) == ASN1_ETYPE_CONSTANT)
+                   {
+                     if (!_asn1_strcmp (p->name, value))
+                       {
+                         value_temp = malloc (SIZEOF_UNSIGNED_LONG_INT);
+                         if (value_temp == NULL)
+                           return ASN1_MEM_ALLOC_ERROR;
+
+                         _asn1_convert_integer (p->value,
+                                                value_temp,
+                                                SIZEOF_UNSIGNED_LONG_INT,
+                                                &len);
+                         break;
+                       }
+                   }
+                 p = p->right;
+               }
+             if (p == NULL)
+               return ASN1_VALUE_NOT_VALID;
+           }
+       }
+      else
+       {                       /* len != 0 */
+         value_temp = malloc (len);
+         if (value_temp == NULL)
+           return ASN1_MEM_ALLOC_ERROR;
+         memcpy (value_temp, value, len);
+       }
 
-    _asn1_octet_der(value_temp+k,len-k,temp,&len2);
-    _asn1_set_value(node,temp,len2);
+      if (value_temp[0] & 0x80)
+       negative = 1;
+      else
+       negative = 0;
 
-    _asn1_afree(temp);
+      if (negative && (type_field (node->type) == ASN1_ETYPE_ENUMERATED))
+       {
+         free (value_temp);
+         return ASN1_VALUE_NOT_VALID;
+       }
 
+      for (k = 0; k < len - 1; k++)
+       if (negative && (value_temp[k] != 0xFF))
+         break;
+       else if (!negative && value_temp[k])
+         break;
+
+      if ((negative && !(value_temp[k] & 0x80)) ||
+         (!negative && (value_temp[k] & 0x80)))
+       k--;
+
+      _asn1_set_value_lv (node, value_temp + k, len - k);
+
+      if (node->type & CONST_DEFAULT)
+       {
+         p = node->down;
+         while (type_field (p->type) != ASN1_ETYPE_DEFAULT)
+           p = p->right;
+         if ((isdigit (p->value[0])) || (p->value[0] == '-'))
+           {
+             default_temp = malloc (SIZEOF_UNSIGNED_LONG_INT);
+             if (default_temp == NULL)
+               {
+                 free (value_temp);
+                 return ASN1_MEM_ALLOC_ERROR;
+               }
+
+             _asn1_convert_integer (p->value, default_temp,
+                                    SIZEOF_UNSIGNED_LONG_INT, &len2);
+           }
+         else
+           {                   /* is an identifier like v1 */
+             if (!(node->type & CONST_LIST))
+               {
+                 free (value_temp);
+                 return ASN1_VALUE_NOT_VALID;
+               }
+             p2 = node->down;
+             while (p2)
+               {
+                 if (type_field (p2->type) == ASN1_ETYPE_CONSTANT)
+                   {
+                     if (!_asn1_strcmp (p2->name, p->value))
+                       {
+                         default_temp = malloc (SIZEOF_UNSIGNED_LONG_INT);
+                         if (default_temp == NULL)
+                           {
+                             free (value_temp);
+                             return ASN1_MEM_ALLOC_ERROR;
+                           }
+
+                         _asn1_convert_integer (p2->value,
+                                                default_temp,
+                                                SIZEOF_UNSIGNED_LONG_INT,
+                                                &len2);
+                         break;
+                       }
+                   }
+                 p2 = p2->right;
+               }
+             if (p2 == NULL)
+               {
+                 free (value_temp);
+                 return ASN1_VALUE_NOT_VALID;
+               }
+           }
 
-    if(node->type&CONST_DEFAULT){
-      p=node->down;
-      while(type_field(p->type)!=TYPE_DEFAULT) p=p->right;
-      if((isdigit(p->value[0])) || (p->value[0]=='-')){
-       default_temp=(unsigned char *)_asn1_alloca(SIZEOF_UNSIGNED_LONG_INT);
-        if (default_temp==NULL) return ASN1_MEM_ALLOC_ERROR;
 
-       _asn1_convert_integer(p->value,default_temp,SIZEOF_UNSIGNED_LONG_INT,&len2);
-      }
-      else{ /* is an identifier like v1 */
-       if(!(node->type&CONST_LIST)) return ASN1_VALUE_NOT_VALID;
-       p2=node->down;
-       while(p2){
-         if(type_field(p2->type)==TYPE_CONSTANT){
-           if((p2->name) && (!strcmp(p2->name,p->value))){
-             default_temp=(unsigned char *)_asn1_alloca(SIZEOF_UNSIGNED_LONG_INT);
-             if (default_temp==NULL) return ASN1_MEM_ALLOC_ERROR;
-
-             _asn1_convert_integer(p2->value,default_temp,SIZEOF_UNSIGNED_LONG_INT,&len2);
+         if ((len - k) == len2)
+           {
+             for (k2 = 0; k2 < len2; k2++)
+               if (value_temp[k + k2] != default_temp[k2])
+                 {
+                   break;
+                 }
+             if (k2 == len2)
+               _asn1_set_value (node, NULL, 0);
+           }
+         free (default_temp);
+       }
+      free (value_temp);
+      break;
+    case ASN1_ETYPE_OBJECT_ID:
+      for (i = 0; i < _asn1_strlen (value); i++)
+       if ((!isdigit (value[i])) && (value[i] != '.') && (value[i] != '+'))
+         return ASN1_VALUE_NOT_VALID;
+      if (node->type & CONST_DEFAULT)
+       {
+         p = node->down;
+         while (type_field (p->type) != ASN1_ETYPE_DEFAULT)
+           p = p->right;
+         if (!_asn1_strcmp (value, p->value))
+           {
+             _asn1_set_value (node, NULL, 0);
              break;
            }
-         }
-         p2=p2->right;
        }
-       if(p2==NULL) return ASN1_VALUE_NOT_VALID;
-      }
-
-
-      if((len-k)==len2){
-       for(k2=0;k2<len2;k2++) 
-         if(value_temp[k+k2]!=default_temp[k2]){
+      _asn1_set_value (node, value, _asn1_strlen (value) + 1);
+      break;
+    case ASN1_ETYPE_UTC_TIME:
+      {
+       len = _asn1_strlen (value);
+       if (len < 11)
+         return ASN1_VALUE_NOT_VALID;
+       for (k = 0; k < 10; k++)
+         if (!isdigit (value[k]))
+           return ASN1_VALUE_NOT_VALID;
+       switch (len)
+         {
+         case 11:
+           if (value[10] != 'Z')
+             return ASN1_VALUE_NOT_VALID;
+           break;
+         case 13:
+           if ((!isdigit (value[10])) || (!isdigit (value[11])) ||
+               (value[12] != 'Z'))
+             return ASN1_VALUE_NOT_VALID;
+           break;
+         case 15:
+           if ((value[10] != '+') && (value[10] != '-'))
+             return ASN1_VALUE_NOT_VALID;
+           for (k = 11; k < 15; k++)
+             if (!isdigit (value[k]))
+               return ASN1_VALUE_NOT_VALID;
+           break;
+         case 17:
+           if ((!isdigit (value[10])) || (!isdigit (value[11])))
+             return ASN1_VALUE_NOT_VALID;
+           if ((value[12] != '+') && (value[12] != '-'))
+             return ASN1_VALUE_NOT_VALID;
+           for (k = 13; k < 17; k++)
+             if (!isdigit (value[k]))
+               return ASN1_VALUE_NOT_VALID;
            break;
+         default:
+           return ASN1_VALUE_NOT_FOUND;
          }
-       if(k2==len2) _asn1_set_value(node,NULL,0);
+       _asn1_set_value (node, value, len);
       }
-      _asn1_afree(default_temp);
-    }
-    _asn1_afree(value_temp);
-    break;
-  case TYPE_OBJECT_ID:
-    for(k=0;k<strlen(value);k++)
-      if((!isdigit(value[k])) && (value[k]!='.') && (value[k]!='+')) 
-       return ASN1_VALUE_NOT_VALID; 
-    if(node->type&CONST_DEFAULT){
-      p=node->down;
-      while(type_field(p->type)!=TYPE_DEFAULT) p=p->right;
-      if(!strcmp(value,p->value)){
-       _asn1_set_value(node,NULL,0);
-       break;
-      } 
-    }
-    _asn1_set_value(node,value,strlen(value)+1);
-    break;
-  case TYPE_TIME:
-    if(node->type&CONST_UTC){
-      if(strlen(value)<11) return ASN1_VALUE_NOT_VALID;
-      for(k=0;k<10;k++) 
-       if(!isdigit(value[k])) return ASN1_VALUE_NOT_VALID;
-      switch(strlen(value)){
-      case 11:
-      if(value[10]!='Z') return ASN1_VALUE_NOT_VALID;
       break;
-      case 13:
-       if((!isdigit(value[10])) || (!isdigit(value[11])) ||
-          (value[12]!='Z')) return ASN1_VALUE_NOT_VALID;
-       break;
-      case 15:
-       if((value[10]!='+') && (value[10]!='-')) return ASN1_VALUE_NOT_VALID;
-       for(k=11;k<15;k++) 
-         if(!isdigit(value[k])) return ASN1_VALUE_NOT_VALID;
-       break;
-      case 17:
-       if((!isdigit(value[10])) || (!isdigit(value[11]))) 
-          return ASN1_VALUE_NOT_VALID;
-       if((value[12]!='+') && (value[12]!='-')) return ASN1_VALUE_NOT_VALID;
-       for(k=13;k<17;k++) 
-         if(!isdigit(value[k])) return ASN1_VALUE_NOT_VALID;
-       break; 
-      default:
-       return ASN1_VALUE_NOT_FOUND;
-      }
-      _asn1_set_value(node,value,strlen(value)+1);
-    }
-    else{  /* GENERALIZED TIME */
-      if(value) _asn1_set_value(node,value,strlen(value)+1);
-    }
-    break;
-  case  TYPE_OCTET_STRING:
-    if(len==0)
-      len=strlen(value);
-    _asn1_length_der(len,NULL,&len2);
-    temp=(unsigned char *)_asn1_alloca(len+len2);
-    if (temp==NULL) return ASN1_MEM_ALLOC_ERROR;
-
-    _asn1_octet_der(value,len,temp,&len2);
-    _asn1_set_value(node,temp,len2);
-    _asn1_afree(temp);
-    break;
-  case  TYPE_GENERALSTRING:
-    if(len==0)
-      len=strlen(value);
-    _asn1_length_der(len,NULL,&len2);
-    temp=(unsigned char *)_asn1_alloca(len+len2);
-    if (temp==NULL) return ASN1_MEM_ALLOC_ERROR;
-
-    _asn1_octet_der(value,len,temp,&len2);
-    _asn1_set_value(node,temp,len2);
-    _asn1_afree(temp);
-    break;
-  case  TYPE_BIT_STRING:
-    if(len==0)
-      len=strlen(value);
-    _asn1_length_der((len>>3)+2,NULL,&len2);
-    temp=(unsigned char *)_asn1_alloca((len>>3)+2+len2);
-    if (temp==NULL) return ASN1_MEM_ALLOC_ERROR;
-
-    _asn1_bit_der(value,len,temp,&len2);
-    _asn1_set_value(node,temp,len2);
-    _asn1_afree(temp);
-    break;
-  case  TYPE_CHOICE:
-    p=node->down;
-    while(p){
-      if(!strcmp(p->name,value)){
-       p2=node->down;
-       while(p2){
-         if(p2!=p){asn1_delete_structure(&p2); p2=node->down;}
-         else p2=p2->right;
+    case ASN1_ETYPE_GENERALIZED_TIME:
+      len = _asn1_strlen (value);
+      _asn1_set_value (node, value, len);
+      break;
+    case ASN1_ETYPE_OCTET_STRING:
+    case ASN1_ETYPE_GENERALSTRING:
+    case ASN1_ETYPE_NUMERIC_STRING:
+    case ASN1_ETYPE_IA5_STRING:
+    case ASN1_ETYPE_TELETEX_STRING:
+    case ASN1_ETYPE_PRINTABLE_STRING:
+    case ASN1_ETYPE_UNIVERSAL_STRING:
+    case ASN1_ETYPE_BMP_STRING:
+    case ASN1_ETYPE_UTF8_STRING:
+    case ASN1_ETYPE_VISIBLE_STRING:
+      if (len == 0)
+       len = _asn1_strlen (value);
+      _asn1_set_value_lv (node, value, len);
+      break;
+    case ASN1_ETYPE_BIT_STRING:
+      if (len == 0)
+       len = _asn1_strlen (value);
+      asn1_length_der ((len >> 3) + 2, NULL, &len2);
+      temp = malloc ((len >> 3) + 2 + len2);
+      if (temp == NULL)
+       return ASN1_MEM_ALLOC_ERROR;
+
+      asn1_bit_der (value, len, temp, &len2);
+      _asn1_set_value_m (node, temp, len2);
+      temp = NULL;
+      break;
+    case ASN1_ETYPE_CHOICE:
+      p = node->down;
+      while (p)
+       {
+         if (!_asn1_strcmp (p->name, value))
+           {
+             p2 = node->down;
+             while (p2)
+               {
+                 if (p2 != p)
+                   {
+                     asn1_delete_structure (&p2);
+                     p2 = node->down;
+                   }
+                 else
+                   p2 = p2->right;
+               }
+             break;
+           }
+         p = p->right;
        }
-       break;
-      }
-      p=p->right;
+      if (!p)
+       return ASN1_ELEMENT_NOT_FOUND;
+      break;
+    case ASN1_ETYPE_ANY:
+      _asn1_set_value_lv (node, value, len);
+      break;
+    case ASN1_ETYPE_SEQUENCE_OF:
+    case ASN1_ETYPE_SET_OF:
+      if (_asn1_strcmp (value, "NEW"))
+       return ASN1_VALUE_NOT_VALID;
+      _asn1_append_sequence_set (node);
+      break;
+    default:
+      return ASN1_ELEMENT_NOT_FOUND;
+      break;
     }
-    if(!p) return ASN1_ELEMENT_NOT_FOUND;
-    break;
-  case TYPE_ANY:
-    _asn1_length_der(len,NULL,&len2);
-    temp=(unsigned char *)_asn1_alloca(len+len2);
-    if (temp==NULL) return ASN1_MEM_ALLOC_ERROR;
-
-    _asn1_octet_der(value,len,temp,&len2);
-    _asn1_set_value(node,temp,len2);
-    _asn1_afree(temp);
-    break;
-  case TYPE_SEQUENCE_OF: case TYPE_SET_OF:
-    if(strcmp(value,"NEW")) return ASN1_VALUE_NOT_VALID;    
-    _asn1_append_sequence_set(node);
-    break;
-  default:
-    return  ASN1_ELEMENT_NOT_FOUND;
-    break;
-  }
 
   return ASN1_SUCCESS;
 }
@@ -509,309 +624,454 @@ asn1_write_value(node_asn *node_root,const char *name,
        if (ptr_size < data_size) { \
                return ASN1_MEM_ERROR; \
        } else { \
-               memcpy( ptr, data, data_size); \
+               if (ptr && data_size > 0) \
+                 memcpy (ptr, data, data_size); \
        }
 
 #define PUT_STR_VALUE( ptr, ptr_size, data) \
-       *len = strlen(data) + 1; \
+       *len = _asn1_strlen (data) + 1; \
        if (ptr_size < *len) { \
                return ASN1_MEM_ERROR; \
        } else { \
                /* this strcpy is checked */ \
-               strcpy(ptr, data); \
+               if (ptr) { \
+                 _asn1_strcpy (ptr, data); \
+               } \
        }
-               
-#define ADD_STR_VALUE( ptr, ptr_size, data) \
-       *len = strlen(data) + 1; \
-       if (ptr_size < strlen(ptr)+(*len)) { \
+
+#define PUT_AS_STR_VALUE( ptr, ptr_size, data, data_size) \
+       *len = data_size + 1; \
+       if (ptr_size < *len) { \
                return ASN1_MEM_ERROR; \
        } else { \
-               /* this strcat is checked */ \
-               strcat(ptr, data); \
+               /* this strcpy is checked */ \
+               if (ptr) { \
+                 if (data_size > 0) \
+                   memcpy (ptr, data, data_size); \
+                 ptr[data_size] = 0; \
+               } \
        }
 
+#define ADD_STR_VALUE( ptr, ptr_size, data) \
+        *len += _asn1_strlen(data); \
+        if (ptr_size < (int) *len) { \
+                (*len)++; \
+                return ASN1_MEM_ERROR; \
+        } else { \
+                /* this strcat is checked */ \
+                if (ptr) _asn1_strcat (ptr, data); \
+        }
+
 /**
-  * asn1_read_value - Returns the value of one element inside a structure
-  * @root: pointer to a structure
-  * @name: the name of the element inside a structure that you want to read.
-  * @ivalue: vector that will contain the element's content. 
-  * VALUE must be a pointer to memory cells already allocated.
-  * @len: number of bytes of *value: value[0]..value[len-1]. Initialy holds the sizeof value.
-  *
-  * Description:
-  *
-  * Returns the value of one element inside a structure.
-  * 
-  * Returns:
-  *
-  *   ASN1_SUCCESS\: set value OK
-  *
-  *   ASN1_ELEMENT_NOT_FOUND\: NAME is not a valid element.
-  *
-  *   ASN1_VALUE_NOT_FOUND\: there isn't any value for the element selected.
-  *
-  *   ASN1_MEM_ERROR\: the value vector isn't big enough to store the result.
-  *   In this case LEN will contain the number of bytes needed.
-  * 
-  * Examples: 
-  *   a description for each type
-  *
-  *\begin{itemize}
-  * \item INTEGER\: VALUE will contain a two's complement form integer.
-  *            integer=-1  -> value[0]=0xFF , len=1
-  *            integer=1   -> value[0]=0x01 , len=1
-  *
-  * \item ENUMERATED\: as INTEGER (but only with not negative numbers)
-  *
-  * \item BOOLEAN\: VALUE will be the null terminated string "TRUE" or "FALSE" and LEN=5 or LEN=6
-  *
-  * \item OBJECT IDENTIFIER\: VALUE will be a null terminated string with each number separated by
-  *                      a dot (i.e. "1.2.3.543.1"). 
-  *                      LEN = strlen(VALUE)+1
-  *
-  * \item UTCTime\: VALUE will be a null terminated string in one of these formats\: 
-  *            "YYMMDDhhmmss+hh'mm'" or "YYMMDDhhmmss-hh'mm'"
-  *            LEN=strlen(VALUE)+1
-  *
-  * \item GeneralizedTime\: VALUE will be a null terminated string in the same format used to set
-  *                    the value
-  *
-  * \item OCTET STRING\: VALUE will contain the octet string and LEN will be the number of octet.
-  *
-  * \item GeneralString\: VALUE will contain the generalstring and LEN will be the number of octet.
-  *
-  * \item BIT STRING\: VALUE will contain the bit string organized by bytes and LEN will be the 
-  *               number of bits.
-  *
-  * \item CHOICE\: if NAME indicates a choice type, VALUE will specify the alternative selected
-  *
-  * \item ANY\: if NAME indicates an any type, VALUE will indicate the DER encoding of the structure 
-  *        actually used.
-  *\end{itemize}
-  * 
-  * If an element is OPTIONAL and the function "read_value" returns ASN1_ELEMENT_NOT_FOUND, it 
-  * means that this element wasn't present in the der encoding that created the structure.
-  * The first element of a SEQUENCE_OF or SET_OF is named "?1". The second one "?2" and so on.
-  * 
-  **/
-asn1_retCode 
-asn1_read_value(node_asn *root,const char *name,void* ivalue, int *len)
+ * asn1_read_value:
+ * @root: pointer to a structure.
+ * @name: the name of the element inside a structure that you want to read.
+ * @ivalue: vector that will contain the element's content, must be a
+ *   pointer to memory cells already allocated (may be %NULL).
+ * @len: number of bytes of *value: value[0]..value[len-1]. Initialy
+ *   holds the sizeof value.
+ *
+ * Returns the value of one element inside a structure. 
+ * If an element is OPTIONAL and this returns
+ * %ASN1_ELEMENT_NOT_FOUND, it means that this element wasn't present
+ * in the der encoding that created the structure.  The first element
+ * of a SEQUENCE_OF or SET_OF is named "?1". The second one "?2" and
+ * so on.
+ *
+ * Note that there can be valid values with length zero. In these case
+ * this function will succeed and @len will be zero.
+ *
+ * INTEGER: VALUE will contain a two's complement form integer.
+ *
+ *            integer=-1  -> value[0]=0xFF , len=1.
+ *            integer=1   -> value[0]=0x01 , len=1.
+ *
+ * ENUMERATED: As INTEGER (but only with not negative numbers).
+ *
+ * BOOLEAN: VALUE will be the null terminated string "TRUE" or
+ *   "FALSE" and LEN=5 or LEN=6.
+ *
+ * OBJECT IDENTIFIER: VALUE will be a null terminated string with
+ *   each number separated by a dot (i.e. "1.2.3.543.1").
+ *
+ *                      LEN = strlen(VALUE)+1
+ *
+ * UTCTime: VALUE will be a null terminated string in one of these
+ *   formats: "YYMMDDhhmmss+hh'mm'" or "YYMMDDhhmmss-hh'mm'".
+ *   LEN=strlen(VALUE)+1.
+ *
+ * GeneralizedTime: VALUE will be a null terminated string in the
+ *   same format used to set the value.
+ *
+ * OCTET STRING: VALUE will contain the octet string and LEN will be
+ *   the number of octets.
+ *
+ * GeneralString: VALUE will contain the generalstring and LEN will
+ *   be the number of octets.
+ *
+ * BIT STRING: VALUE will contain the bit string organized by bytes
+ *   and LEN will be the number of bits.
+ *
+ * CHOICE: If NAME indicates a choice type, VALUE will specify the
+ *   alternative selected.
+ *
+ * ANY: If NAME indicates an any type, VALUE will indicate the DER
+ *   encoding of the structure actually used.
+ *
+ * Returns: %ASN1_SUCCESS if value is returned,
+ *   %ASN1_ELEMENT_NOT_FOUND if @name is not a valid element,
+ *   %ASN1_VALUE_NOT_FOUND if there isn't any value for the element
+ *   selected, and %ASN1_MEM_ERROR if The value vector isn't big enough
+ *   to store the result, and in this case @len will contain the number of
+ *   bytes needed.
+ **/
+int
+asn1_read_value (asn1_node root, const char *name, void *ivalue, int *len)
 {
-  node_asn *node,*p,*p2;
-  int len2,len3;
+  return asn1_read_value_type (root, name, ivalue, len, NULL);
+}
+
+/**
+ * asn1_read_value_type:
+ * @root: pointer to a structure.
+ * @name: the name of the element inside a structure that you want to read.
+ * @ivalue: vector that will contain the element's content, must be a
+ *   pointer to memory cells already allocated (may be %NULL).
+ * @len: number of bytes of *value: value[0]..value[len-1]. Initialy
+ *   holds the sizeof value.
+ * @etype: The type of the value read (ASN1_ETYPE)
+ *
+ * Returns the value of one element inside a structure. 
+ * If an element is OPTIONAL and this returns
+ * %ASN1_ELEMENT_NOT_FOUND, it means that this element wasn't present
+ * in the der encoding that created the structure.  The first element
+ * of a SEQUENCE_OF or SET_OF is named "?1". The second one "?2" and
+ * so on.
+ *
+ * Note that there can be valid values with length zero. In these case
+ * this function will succeed and @len will be zero.
+ *
+ *
+ * INTEGER: VALUE will contain a two's complement form integer.
+ *
+ *            integer=-1  -> value[0]=0xFF , len=1.
+ *            integer=1   -> value[0]=0x01 , len=1.
+ *
+ * ENUMERATED: As INTEGER (but only with not negative numbers).
+ *
+ * BOOLEAN: VALUE will be the null terminated string "TRUE" or
+ *   "FALSE" and LEN=5 or LEN=6.
+ *
+ * OBJECT IDENTIFIER: VALUE will be a null terminated string with
+ *   each number separated by a dot (i.e. "1.2.3.543.1").
+ *
+ *                      LEN = strlen(VALUE)+1
+ *
+ * UTCTime: VALUE will be a null terminated string in one of these
+ *   formats: "YYMMDDhhmmss+hh'mm'" or "YYMMDDhhmmss-hh'mm'".
+ *   LEN=strlen(VALUE)+1.
+ *
+ * GeneralizedTime: VALUE will be a null terminated string in the
+ *   same format used to set the value.
+ *
+ * OCTET STRING: VALUE will contain the octet string and LEN will be
+ *   the number of octets.
+ *
+ * GeneralString: VALUE will contain the generalstring and LEN will
+ *   be the number of octets.
+ *
+ * BIT STRING: VALUE will contain the bit string organized by bytes
+ *   and LEN will be the number of bits.
+ *
+ * CHOICE: If NAME indicates a choice type, VALUE will specify the
+ *   alternative selected.
+ *
+ * ANY: If NAME indicates an any type, VALUE will indicate the DER
+ *   encoding of the structure actually used.
+ *
+ * Returns: %ASN1_SUCCESS if value is returned,
+ *   %ASN1_ELEMENT_NOT_FOUND if @name is not a valid element,
+ *   %ASN1_VALUE_NOT_FOUND if there isn't any value for the element
+ *   selected, and %ASN1_MEM_ERROR if The value vector isn't big enough
+ *   to store the result, and in this case @len will contain the number of
+ *   bytes needed.
+ **/
+int
+asn1_read_value_type (asn1_node root, const char *name, void *ivalue,
+                     int *len, unsigned int *etype)
+{
+  asn1_node node, p, p2;
+  int len2, len3, result;
   int value_size = *len;
-  unsigned char* value = ivalue;
+  unsigned char *value = ivalue;
+  unsigned type;
 
-  node=_asn1_find_node(root,name);
-  if(node==NULL) return  ASN1_ELEMENT_NOT_FOUND;
+  node = asn1_find_node (root, name);
+  if (node == NULL)
+    return ASN1_ELEMENT_NOT_FOUND;
 
-  if((type_field(node->type)!=TYPE_NULL) && 
-     (type_field(node->type)!=TYPE_CHOICE) &&  
-     !(node->type&CONST_DEFAULT) && !(node->type&CONST_ASSIGN) &&
-     (node->value==NULL)) 
+  type = type_field (node->type);
+
+  if ((type != ASN1_ETYPE_NULL) &&
+      (type != ASN1_ETYPE_CHOICE) &&
+      !(node->type & CONST_DEFAULT) && !(node->type & CONST_ASSIGN) &&
+      (node->value == NULL))
     return ASN1_VALUE_NOT_FOUND;
 
-  switch(type_field(node->type)){
-  case TYPE_NULL:
-    PUT_STR_VALUE( value, value_size, "NULL");
-    break;
-  case TYPE_BOOLEAN:
-    if((node->type&CONST_DEFAULT) && (node->value==NULL)){
-      p=node->down;
-      while(type_field(p->type)!=TYPE_DEFAULT) p=p->right;
-      if(p->type&CONST_TRUE) {
-       PUT_STR_VALUE( value, value_size, "TRUE");
-      } else {
-       PUT_STR_VALUE(value, value_size, "FALSE");
-      }
-    }
-    else if(node->value[0]=='T') {
-       PUT_STR_VALUE(value, value_size, "TRUE");
-    }
-    else {
-       PUT_STR_VALUE(value, value_size, "FALSE");
-    }
-    break;
-  case TYPE_INTEGER: case TYPE_ENUMERATED:
-    if((node->type&CONST_DEFAULT) && (node->value==NULL)){
-      p=node->down;
-      while(type_field(p->type)!=TYPE_DEFAULT) p=p->right;
-      if((isdigit(p->value[0])) || (p->value[0]=='-') || (p->value[0]=='+')){
-       if (_asn1_convert_integer(p->value,value,value_size, len) != 
-           ASN1_SUCCESS) 
-         return ASN1_MEM_ERROR;
-      }
-      else{ /* is an identifier like v1 */
-       p2=node->down;
-       while(p2){
-         if(type_field(p2->type)==TYPE_CONSTANT){
-           if((p2->name) && (!strcmp(p2->name,p->value))){
-             if (_asn1_convert_integer(p2->value,value,value_size, len) != 
-                 ASN1_SUCCESS) 
-               return ASN1_MEM_ERROR;
-             break;
+  if (etype)
+    *etype = type;
+  switch (type)
+    {
+    case ASN1_ETYPE_NULL:
+      PUT_STR_VALUE (value, value_size, "NULL");
+      break;
+    case ASN1_ETYPE_BOOLEAN:
+      if ((node->type & CONST_DEFAULT) && (node->value == NULL))
+       {
+         p = node->down;
+         while (type_field (p->type) != ASN1_ETYPE_DEFAULT)
+           p = p->right;
+         if (p->type & CONST_TRUE)
+           {
+             PUT_STR_VALUE (value, value_size, "TRUE");
+           }
+         else
+           {
+             PUT_STR_VALUE (value, value_size, "FALSE");
            }
-         }
-         p2=p2->right;
        }
-      }
-    }
-    else{
-      len2=-1;
-      if (_asn1_get_octet_der(node->value,&len2,value, value_size, len)!=ASN1_SUCCESS) return ASN1_MEM_ERROR;
-    }
-    break;
-  case TYPE_OBJECT_ID:
-    if(node->type&CONST_ASSIGN){
-      value[0]=0;
-      p=node->down;
-      while(p){
-       if(type_field(p->type)==TYPE_CONSTANT){
-         ADD_STR_VALUE(value,value_size,p->value);       
-         if(p->right) {
-         ADD_STR_VALUE(value,value_size,".");
-         }
+      else if (node->value[0] == 'T')
+       {
+         PUT_STR_VALUE (value, value_size, "TRUE");
        }
-       p=p->right;
-      }
-      *len = strlen(value) + 1;
-    } 
-    else if((node->type&CONST_DEFAULT) && (node->value==NULL)){
-      p=node->down;
-      while(type_field(p->type)!=TYPE_DEFAULT) p=p->right;
-      PUT_STR_VALUE(value, value_size, p->value);
-      }
-    else {
-      PUT_STR_VALUE(value, value_size, node->value);
+      else
+       {
+         PUT_STR_VALUE (value, value_size, "FALSE");
+       }
+      break;
+    case ASN1_ETYPE_INTEGER:
+    case ASN1_ETYPE_ENUMERATED:
+      if ((node->type & CONST_DEFAULT) && (node->value == NULL))
+       {
+         p = node->down;
+         while (type_field (p->type) != ASN1_ETYPE_DEFAULT)
+           p = p->right;
+         if ((isdigit (p->value[0])) || (p->value[0] == '-')
+             || (p->value[0] == '+'))
+           {
+             result = _asn1_convert_integer
+                 (p->value, value, value_size, len);
+              if (result != ASN1_SUCCESS)
+               return result;
+           }
+         else
+           {                   /* is an identifier like v1 */
+             p2 = node->down;
+             while (p2)
+               {
+                 if (type_field (p2->type) == ASN1_ETYPE_CONSTANT)
+                   {
+                     if (!_asn1_strcmp (p2->name, p->value))
+                       {
+                         result = _asn1_convert_integer
+                             (p2->value, value, value_size,
+                              len);
+                         if (result != ASN1_SUCCESS)
+                           return result;
+                         break;
+                       }
+                   }
+                 p2 = p2->right;
+               }
+           }
+       }
+      else
+       {
+         len2 = -1;
+         result = asn1_get_octet_der
+             (node->value, node->value_len, &len2, value, value_size,
+              len);
+          if (result != ASN1_SUCCESS)
+           return result;
+       }
+      break;
+    case ASN1_ETYPE_OBJECT_ID:
+      if (node->type & CONST_ASSIGN)
+       {
+         *len = 0;
+         if (value)
+               value[0] = 0;
+         p = node->down;
+         while (p)
+           {
+             if (type_field (p->type) == ASN1_ETYPE_CONSTANT)
+               {
+                 ADD_STR_VALUE (value, value_size, p->value);
+                 if (p->right)
+                   {
+                     ADD_STR_VALUE (value, value_size, ".");
+                   }
+               }
+             p = p->right;
+           }
+         (*len)++;
+       }
+      else if ((node->type & CONST_DEFAULT) && (node->value == NULL))
+       {
+         p = node->down;
+         while (type_field (p->type) != ASN1_ETYPE_DEFAULT)
+           p = p->right;
+         PUT_STR_VALUE (value, value_size, p->value);
+       }
+      else
+       {
+         PUT_STR_VALUE (value, value_size, node->value);
+       }
+      break;
+    case ASN1_ETYPE_GENERALIZED_TIME:
+    case ASN1_ETYPE_UTC_TIME:
+      PUT_AS_STR_VALUE (value, value_size, node->value, node->value_len);
+      break;
+    case ASN1_ETYPE_OCTET_STRING:
+    case ASN1_ETYPE_GENERALSTRING:
+    case ASN1_ETYPE_NUMERIC_STRING:
+    case ASN1_ETYPE_IA5_STRING:
+    case ASN1_ETYPE_TELETEX_STRING:
+    case ASN1_ETYPE_PRINTABLE_STRING:
+    case ASN1_ETYPE_UNIVERSAL_STRING:
+    case ASN1_ETYPE_BMP_STRING:
+    case ASN1_ETYPE_UTF8_STRING:
+    case ASN1_ETYPE_VISIBLE_STRING:
+      len2 = -1;
+      result = asn1_get_octet_der
+         (node->value, node->value_len, &len2, value, value_size,
+          len);
+      if (result != ASN1_SUCCESS)
+       return result;
+      break;
+    case ASN1_ETYPE_BIT_STRING:
+      len2 = -1;
+      result = asn1_get_bit_der
+         (node->value, node->value_len, &len2, value, value_size,
+          len);
+      if (result != ASN1_SUCCESS)
+       return result;
+      break;
+    case ASN1_ETYPE_CHOICE:
+      PUT_STR_VALUE (value, value_size, node->down->name);
+      break;
+    case ASN1_ETYPE_ANY:
+      len3 = -1;
+      len2 = asn1_get_length_der (node->value, node->value_len, &len3);
+      if (len2 < 0)
+       return ASN1_DER_ERROR;
+      PUT_VALUE (value, value_size, node->value + len3, len2);
+      break;
+    default:
+      return ASN1_ELEMENT_NOT_FOUND;
+      break;
     }
-    break;
-  case TYPE_TIME:
-    PUT_STR_VALUE( value, value_size, node->value);
-    break;
-  case TYPE_OCTET_STRING:
-    len2=-1;
-    if (_asn1_get_octet_der(node->value,&len2,value, value_size, len)!=ASN1_SUCCESS) return ASN1_MEM_ERROR;
-    break;
-  case TYPE_GENERALSTRING:
-    len2=-1;
-    if (_asn1_get_octet_der(node->value,&len2,value, value_size, len)!=ASN1_SUCCESS) return ASN1_MEM_ERROR;
-    break;
-  case TYPE_BIT_STRING:
-    len2=-1;
-    if (_asn1_get_bit_der(node->value,&len2,value,value_size,len)!=ASN1_SUCCESS) return ASN1_MEM_ERROR;
-    break;
-  case TYPE_CHOICE:
-    PUT_STR_VALUE( value, value_size, node->down->name);
-    break; 
-  case TYPE_ANY:
-    len3=-1;
-    len2=_asn1_get_length_der(node->value,&len3);
-    PUT_VALUE( value, value_size, node->value+len3, len2);
-    break;
-  default:
-    return  ASN1_ELEMENT_NOT_FOUND;
-    break;
-  }
   return ASN1_SUCCESS;
 }
 
 
 /**
-  * asn1_read_tag - Returns the TAG of one element inside a structure
-  * @root: pointer to a structure
-  * @name: the name of the element inside a structure.
-  * @tagValue:  variable that will contain the TAG value. 
-  * @classValue: variable that will specify the TAG type.
-  *
-  * Description:
-  *
-  * Returns the TAG and the CLASS of one element inside a structure.
-  * CLASS can have one of these constants: ASN1_CLASS_APPLICATION,
-  * ASN1_CLASS_UNIVERSAL, ASN1_CLASS_PRIVATE or ASN1_CLASS_CONTEXT_SPECIFIC.
-  * 
-  * Returns:
-  *
-  *   ASN1_SUCCESS\: set value OK
-  *
-  *   ASN1_ELEMENT_NOT_FOUND\: NAME is not a valid element.
-  * 
-  **/
-asn1_retCode 
-asn1_read_tag(node_asn *root,const char *name,int *tagValue, int *classValue)
+ * asn1_read_tag:
+ * @root: pointer to a structure
+ * @name: the name of the element inside a structure.
+ * @tagValue:  variable that will contain the TAG value.
+ * @classValue: variable that will specify the TAG type.
+ *
+ * Returns the TAG and the CLASS of one element inside a structure.
+ * CLASS can have one of these constants: %ASN1_CLASS_APPLICATION,
+ * %ASN1_CLASS_UNIVERSAL, %ASN1_CLASS_PRIVATE or
+ * %ASN1_CLASS_CONTEXT_SPECIFIC.
+ *
+ * Returns: %ASN1_SUCCESS if successful, %ASN1_ELEMENT_NOT_FOUND if
+ *   @name is not a valid element.
+ **/
+int
+asn1_read_tag (asn1_node root, const char *name, int *tagValue,
+              int *classValue)
 {
-  node_asn *node,*p,*pTag;
-  node=_asn1_find_node(root,name);
-  if(node==NULL) return  ASN1_ELEMENT_NOT_FOUND;
+  asn1_node node, p, pTag;
+
+  node = asn1_find_node (root, name);
+  if (node == NULL)
+    return ASN1_ELEMENT_NOT_FOUND;
 
-  p=node->down;
+  p = node->down;
 
   /* pTag will points to the IMPLICIT TAG */
-  pTag=NULL;
-  if(node->type&CONST_TAG){
-    while(p){
-      if(type_field(p->type)==TYPE_TAG){
-       if((p->type&CONST_IMPLICIT) && (pTag==NULL))
-         pTag=p;
-       else if(p->type&CONST_EXPLICIT)
-         pTag=NULL;
-      }
-      p=p->right;
-    }
-  }
-
-  if(pTag){
-    *tagValue=strtoul(pTag->value,NULL,10);
-  
-    if(pTag->type&CONST_APPLICATION) *classValue=ASN1_CLASS_APPLICATION;
-    else if(pTag->type&CONST_UNIVERSAL) *classValue=ASN1_CLASS_UNIVERSAL;
-    else if(pTag->type&CONST_PRIVATE) *classValue=ASN1_CLASS_PRIVATE;
-    else *classValue=ASN1_CLASS_CONTEXT_SPECIFIC;
-  }
-  else{
-    *classValue=ASN1_CLASS_UNIVERSAL;
-
-    switch(type_field(node->type)){
-    case TYPE_NULL:
-      *tagValue=ASN1_TAG_NULL;break;
-    case TYPE_BOOLEAN:
-      *tagValue=ASN1_TAG_BOOLEAN;break;
-    case TYPE_INTEGER:
-      *tagValue=ASN1_TAG_INTEGER;break;
-    case TYPE_ENUMERATED:
-      *tagValue=ASN1_TAG_ENUMERATED;break;
-    case TYPE_OBJECT_ID:
-      *tagValue=ASN1_TAG_OBJECT_ID;break;
-    case TYPE_TIME:
-      if(node->type&CONST_UTC){
-       *tagValue=ASN1_TAG_UTCTime;
-      }
-      else *tagValue=ASN1_TAG_GENERALIZEDTime;
-      break;
-    case TYPE_OCTET_STRING:
-      *tagValue=ASN1_TAG_OCTET_STRING;break;
-    case TYPE_GENERALSTRING:
-      *tagValue=ASN1_TAG_GENERALSTRING;break;
-    case TYPE_BIT_STRING:
-      *tagValue=ASN1_TAG_BIT_STRING;break;
-    case TYPE_SEQUENCE: case TYPE_SEQUENCE_OF:
-      *tagValue=ASN1_TAG_SEQUENCE;break;
-    case TYPE_SET: case TYPE_SET_OF:
-      *tagValue=ASN1_TAG_SET;break;
-    case TYPE_TAG:
-    case TYPE_CHOICE:
-    case TYPE_ANY:
-      break;
-    default:
-      break;
+  pTag = NULL;
+  if (node->type & CONST_TAG)
+    {
+      while (p)
+       {
+         if (type_field (p->type) == ASN1_ETYPE_TAG)
+           {
+             if ((p->type & CONST_IMPLICIT) && (pTag == NULL))
+               pTag = p;
+             else if (p->type & CONST_EXPLICIT)
+               pTag = NULL;
+           }
+         p = p->right;
+       }
     }
-  }
 
+  if (pTag)
+    {
+      *tagValue = _asn1_strtoul (pTag->value, NULL, 10);
+
+      if (pTag->type & CONST_APPLICATION)
+       *classValue = ASN1_CLASS_APPLICATION;
+      else if (pTag->type & CONST_UNIVERSAL)
+       *classValue = ASN1_CLASS_UNIVERSAL;
+      else if (pTag->type & CONST_PRIVATE)
+       *classValue = ASN1_CLASS_PRIVATE;
+      else
+       *classValue = ASN1_CLASS_CONTEXT_SPECIFIC;
+    }
+  else
+    {
+      unsigned type = type_field (node->type);
+      *classValue = ASN1_CLASS_UNIVERSAL;
+
+      switch (type)
+       {
+       CASE_HANDLED_ETYPES:
+         *tagValue = _asn1_tags[type].tag;
+         break;
+       case ASN1_ETYPE_TAG:
+       case ASN1_ETYPE_CHOICE:
+       case ASN1_ETYPE_ANY:
+         *tagValue = -1;
+         break;
+       default:
+         break;
+       }
+    }
 
   return ASN1_SUCCESS;
-
 }
 
+/**
+ * asn1_read_node_value:
+ * @node: pointer to a node.
+ * @data: a point to a asn1_data_node_st
+ *
+ * Returns the value a data node inside a asn1_node structure.
+ * The data returned should be handled as constant values.
+ *
+ * Returns: %ASN1_SUCCESS if the node exists.
+ **/
+int
+asn1_read_node_value (asn1_node node, asn1_data_node_st * data)
+{
+  data->name = node->name;
+  data->value = node->value;
+  data->value_len = node->value_len;
+  data->type = type_field (node->type);
 
-
-
+  return ASN1_SUCCESS;
+}