if( PR_SUCCESS != nssUTF8_Size(value, &size) ) {
size = nssUTF8_Size(value, &status); if( PR_SUCCESS != status ) {
nssATAV_CreateFromUTF8(  NSSArena *arenaOpt,  const NSSUTF8 *stringATAV){  char *c;  NSSUTF8 *type;  NSSUTF8 *value;  PRUint32 i;  const NSSOID *oid = (NSSOID *)NULL;  NSSATAV *rv;  NSSItem xitem;  xitem.data = (void *)NULL;  for( c = (char *)stringATAV; '\0' != *c; c++ ) {    if( '=' == *c ) {#ifdef PEDANTIC      /*       * Theoretically, one could have an '=' in an        * attribute string alias.  We don't, yet, though.       */      if( (char *)stringATAV == c ) {        nss_SetError(NSS_ERROR_INVALID_STRING);        return (NSSATAV *)NULL;      } else {        if( '\\' == c[-1] ) {          continue;        }      }#endif /* PEDANTIC */      break;    }  }  if( '\0' == *c ) {    nss_SetError(NSS_ERROR_INVALID_UTF8);    return (NSSATAV *)NULL;  } else {    c++;    value = (NSSUTF8 *)c;  }  i = ((NSSUTF8 *)c - stringATAV);  type = (NSSUTF8 *)nss_ZAlloc((NSSArena *)NULL, i);  if( (NSSUTF8 *)NULL == type ) {    return (NSSATAV *)NULL;  }  (void)nsslibc_memcpy(type, stringATAV, i-1);  c = (char *)stringATAV;  if( (('0' <= *c) && (*c <= '9')) || ('#' == *c) ) {    oid = nssOID_CreateFromUTF8(type);    if( (NSSOID *)NULL == oid ) {      nss_ZFreeIf(type);      return (NSSATAV *)NULL;    }  } else {    for( i = 0; i < nss_attribute_type_alias_count; i++ ) {      const nssAttributeTypeAliasTable *e = &nss_attribute_type_aliases[i];      PRBool match = PR_FALSE;      if( PR_SUCCESS != nssUTF8_CaseIgnoreMatch(type, e->alias,                                                 &match) ) {        nss_ZFreeIf(type);        return (NSSATAV *)NULL;      }      if( PR_TRUE == match ) {        oid = *(e->oid);        break;      }    }    if( (NSSOID *)NULL == oid ) {      nss_ZFreeIf(type);      nss_SetError(NSS_ERROR_UNKNOWN_ATTRIBUTE);      return (NSSATAV *)NULL;    }  }  nss_ZFreeIf(type);  type = (NSSUTF8 *)NULL;  rv = nss_ZNEW(arenaOpt, NSSATAV);  if( (NSSATAV *)NULL == rv ) {    return (NSSATAV *)NULL;  }  rv->oid = oid;  if( '#' == *value ) { /* XXX fgmr.. was it '#'?  or backslash? */    PRUint32 size;    PRUint32 len;    PRUint8 *c;    PRUint8 *d;    /* It's in hex */    value++;    if( PR_TRUE != nss_atav_utf8_string_is_hex(value) ) {      (void)nss_ZFreeIf(rv);      nss_SetError(NSS_ERROR_INVALID_STRING);      return (NSSATAV *)NULL;    }    if( PR_SUCCESS != nssUTF8_Size(value, &size) ) {      /*        * Only returns an error on bad pointer (nope) or string       * too long.  The defined limits for known attributes are       * small enough to fit in PRUint32, and when undefined we       * get to apply our own practical limits.  Ergo, I say the        * string is invalid.       */      (void)nss_ZFreeIf(rv);      nss_SetError(NSS_ERROR_INVALID_STRING);      return (NSSATAV *)NULL;    }    if( ((size-1) & 1) ) {      /* odd length */      (void)nss_ZFreeIf(rv);      nss_SetError(NSS_ERROR_INVALID_STRING);      return (NSSATAV *)NULL;    }    len = (size-1)/2;    rv->value = (NSSUTF8 *)nss_ZAlloc(arenaOpt, len+1);    if( (NSSUTF8 *)NULL == rv->value ) {      (void)nss_ZFreeIf(rv);      return (NSSATAV *)NULL;    }    xitem.size = len;    xitem.data = (void *)rv->value;    for( c = rv->value, d = value; len--; c++, d += 2 ) {      *c = nss_atav_fromhex(d);    }    *c = 0;  } else {    PRUint32 i, len;    PRUint8 *s;    /*     * XXX fgmr-- okay, this is a little wasteful, and should     * probably be abstracted out a bit.  Later.     */    rv->value = nssUTF8_Duplicate(value, arenaOpt);    if( (NSSUTF8 *)NULL == rv->value ) {      (void)nss_ZFreeIf(rv);      return (NSSATAV *)NULL;    }    if( PR_SUCCESS != nssUTF8_Size(rv->value, &len) ) {      (void)nss_ZFreeIf(rv->value);      (void)nss_ZFreeIf(rv);      return (NSSATAV *)NULL;    }    s = (PRUint8 *)rv->value;    for( i = 0; i < len; i++ ) {      if( '\\' == s[i] ) {        (void)nsslibc_memcpy(&s[i], &s[i+1], len-i-1);      }    }  }  /* Now just BER-encode the baby and we're through.. */  {    const struct nss_attribute_data_str *which =       (struct nss_attribute_data_str *)NULL;    PRUint32 i;    NSSArena *a;    NSSDER *oidder;    NSSItem *vitem;    atav_holder ah;    NSSDER *status;    for( i = 0; i < nss_attribute_data_quantity; i++ ) {      if( *(nss_attribute_data[ i ].oid) == rv->oid ) {        which = &nss_attribute_data[i];        break;      }    }    a = NSSArena_Create();    if( (NSSArena *)NULL == a ) {      (void)nss_ZFreeIf(rv->value);      (void)nss_ZFreeIf(rv);      return (NSSATAV *)NULL;    }    oidder = nssOID_GetDEREncoding(rv->oid, (NSSDER *)NULL, a);    if( (NSSDER *)NULL == oidder ) {      (void)NSSArena_Destroy(a);      (void)nss_ZFreeIf(rv->value);      (void)nss_ZFreeIf(rv);      return (NSSATAV *)NULL;    }    if( (struct nss_attribute_data_str *)NULL == which ) {      /*       * We'll just have to take the user data as an octet stream.       */      if( (void *)NULL == xitem.data ) {        /*         * This means that an ATTR entry has been added to oids.txt,         * but no corresponding entry has been added to the array         * ns_attribute_data[] above.         */        nss_SetError(NSS_ERROR_INTERNAL_ERROR);        (void)NSSArena_Destroy(a);        (void)nss_ZFreeIf(rv->value);        (void)nss_ZFreeIf(rv);        return (NSSATAV *)NULL;      }      vitem = nssASN1_EncodeDER(a, (NSSDER *)NULL, &xitem,                                 nssASN1Template_OctetString);      if( (NSSItem *)NULL == vitem ) {        (void)NSSArena_Destroy(a);        (void)nss_ZFreeIf(rv->value);        (void)nss_ZFreeIf(rv);        return (NSSATAV *)NULL;      }      rv->stringForm = nssStringType_Unknown;    } else {      PRUint32 length = 0;            if( PR_SUCCESS != nssUTF8_Length(rv->value, &length) ) {        (void)NSSArena_Destroy(a);        (void)nss_ZFreeIf(rv->value);        (void)nss_ZFreeIf(rv);        return (NSSATAV *)NULL;      }      if( ((0 != which->minStringLength) &&            (length < which->minStringLength)) ||          ((0 != which->maxStringLength) &&           (length > which->maxStringLength)) ) {        nss_SetError(NSS_ERROR_INVALID_STRING);        (void)NSSArena_Destroy(a);        (void)nss_ZFreeIf(rv->value);        (void)nss_ZFreeIf(rv);        return (NSSATAV *)NULL;      }      vitem = nssUTF8_GetDEREncoding(a, which->stringType, rv->value);      if( (NSSItem *)NULL == vitem ) {        (void)NSSArena_Destroy(a);        (void)nss_ZFreeIf(rv->value);        (void)nss_ZFreeIf(rv);        return (NSSATAV *)NULL;      }      if( nssStringType_DirectoryString == which->stringType ) {        rv->stringForm = nssStringType_UTF8String;      } else {        rv->stringForm = which->stringType;      }    }    ah.oid = *oidder;    ah.value = *vitem;    status = nssASN1_EncodeDER(arenaOpt, &rv->ber, &ah,                                nss_atav_template);    if( (NSSDER *)NULL == status ) {      (void)NSSArena_Destroy(a);      (void)nss_ZFreeIf(rv->value);      (void)nss_ZFreeIf(rv);      return (NSSATAV *)NULL;    }    (void)NSSArena_Destroy(a);  }  return rv;}