Blame nss/lib/base/utf8.c

Packit 40b132
/* This Source Code Form is subject to the terms of the Mozilla Public
Packit 40b132
 * License, v. 2.0. If a copy of the MPL was not distributed with this
Packit 40b132
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
Packit 40b132
Packit 40b132
/*
Packit 40b132
 * utf8.c
Packit 40b132
 *
Packit 40b132
 * This file contains some additional utility routines required for
Packit 40b132
 * handling UTF8 strings.
Packit 40b132
 */
Packit 40b132
Packit 40b132
#ifndef BASE_H
Packit 40b132
#include "base.h"
Packit 40b132
#endif /* BASE_H */
Packit 40b132
Packit 40b132
#include "plstr.h"
Packit 40b132
Packit 40b132
/*
Packit 40b132
 * NOTES:
Packit 40b132
 *
Packit 40b132
 * There's an "is hex string" function in pki1/atav.c.  If we need
Packit 40b132
 * it in more places, pull that one out.
Packit 40b132
 */
Packit 40b132
Packit 40b132
/*
Packit 40b132
 * nssUTF8_CaseIgnoreMatch
Packit 40b132
 * 
Packit 40b132
 * Returns true if the two UTF8-encoded strings pointed to by the 
Packit 40b132
 * two specified NSSUTF8 pointers differ only in typcase.
Packit 40b132
 *
Packit 40b132
 * The error may be one of the following values:
Packit 40b132
 *  NSS_ERROR_INVALID_POINTER
Packit 40b132
 *
Packit 40b132
 * Return value:
Packit 40b132
 *  PR_TRUE if the strings match, ignoring case
Packit 40b132
 *  PR_FALSE if they don't
Packit 40b132
 *  PR_FALSE upon error
Packit 40b132
 */
Packit 40b132
Packit 40b132
NSS_IMPLEMENT PRBool
Packit 40b132
nssUTF8_CaseIgnoreMatch
Packit 40b132
(
Packit 40b132
  const NSSUTF8 *a,
Packit 40b132
  const NSSUTF8 *b,
Packit 40b132
  PRStatus *statusOpt
Packit 40b132
)
Packit 40b132
{
Packit 40b132
#ifdef NSSDEBUG
Packit 40b132
  if( ((const NSSUTF8 *)NULL == a) ||
Packit 40b132
      ((const NSSUTF8 *)NULL == b) ) {
Packit 40b132
    nss_SetError(NSS_ERROR_INVALID_POINTER);
Packit 40b132
    if( (PRStatus *)NULL != statusOpt ) {
Packit 40b132
      *statusOpt = PR_FAILURE;
Packit 40b132
    }
Packit 40b132
    return PR_FALSE;
Packit 40b132
  }
Packit 40b132
#endif /* NSSDEBUG */
Packit 40b132
Packit 40b132
  if( (PRStatus *)NULL != statusOpt ) {
Packit 40b132
    *statusOpt = PR_SUCCESS;
Packit 40b132
  }
Packit 40b132
Packit 40b132
  /*
Packit 40b132
   * XXX fgmr
Packit 40b132
   *
Packit 40b132
   * This is, like, so wrong!
Packit 40b132
   */
Packit 40b132
  if( 0 == PL_strcasecmp((const char *)a, (const char *)b) ) {
Packit 40b132
    return PR_TRUE;
Packit 40b132
  } else {
Packit 40b132
    return PR_FALSE;
Packit 40b132
  }
Packit 40b132
}
Packit 40b132
Packit 40b132
/*
Packit 40b132
 * nssUTF8_PrintableMatch
Packit 40b132
 *
Packit 40b132
 * Returns true if the two Printable strings pointed to by the 
Packit 40b132
 * two specified NSSUTF8 pointers match when compared with the 
Packit 40b132
 * rules for Printable String (leading and trailing spaces are 
Packit 40b132
 * disregarded, extents of whitespace match irregardless of length, 
Packit 40b132
 * and case is not significant), then PR_TRUE will be returned.
Packit 40b132
 * Otherwise, PR_FALSE will be returned.  Upon failure, PR_FALSE
Packit 40b132
 * will be returned.  If the optional statusOpt argument is not
Packit 40b132
 * NULL, then PR_SUCCESS or PR_FAILURE will be stored in that
Packit 40b132
 * location.
Packit 40b132
 *
Packit 40b132
 * The error may be one of the following values:
Packit 40b132
 *  NSS_ERROR_INVALID_POINTER
Packit 40b132
 *
Packit 40b132
 * Return value:
Packit 40b132
 *  PR_TRUE if the strings match, ignoring case
Packit 40b132
 *  PR_FALSE if they don't
Packit 40b132
 *  PR_FALSE upon error
Packit 40b132
 */
Packit 40b132
Packit 40b132
NSS_IMPLEMENT PRBool
Packit 40b132
nssUTF8_PrintableMatch
Packit 40b132
(
Packit 40b132
  const NSSUTF8 *a,
Packit 40b132
  const NSSUTF8 *b,
Packit 40b132
  PRStatus *statusOpt
Packit 40b132
)
Packit 40b132
{
Packit 40b132
  PRUint8 *c;
Packit 40b132
  PRUint8 *d;
Packit 40b132
Packit 40b132
#ifdef NSSDEBUG
Packit 40b132
  if( ((const NSSUTF8 *)NULL == a) ||
Packit 40b132
      ((const NSSUTF8 *)NULL == b) ) {
Packit 40b132
    nss_SetError(NSS_ERROR_INVALID_POINTER);
Packit 40b132
    if( (PRStatus *)NULL != statusOpt ) {
Packit 40b132
      *statusOpt = PR_FAILURE;
Packit 40b132
    }
Packit 40b132
    return PR_FALSE;
Packit 40b132
  }
Packit 40b132
#endif /* NSSDEBUG */
Packit 40b132
Packit 40b132
  if( (PRStatus *)NULL != statusOpt ) {
Packit 40b132
    *statusOpt = PR_SUCCESS;
Packit 40b132
  }
Packit 40b132
Packit 40b132
  c = (PRUint8 *)a;
Packit 40b132
  d = (PRUint8 *)b;
Packit 40b132
Packit 40b132
  while( ' ' == *c ) {
Packit 40b132
    c++;
Packit 40b132
  }
Packit 40b132
Packit 40b132
  while( ' ' == *d ) {
Packit 40b132
    d++;
Packit 40b132
  }
Packit 40b132
Packit 40b132
  while( ('\0' != *c) && ('\0' != *d) ) {
Packit 40b132
    PRUint8 e, f;
Packit 40b132
Packit 40b132
    e = *c;
Packit 40b132
    f = *d;
Packit 40b132
    
Packit 40b132
    if( ('a' <= e) && (e <= 'z') ) {
Packit 40b132
      e -= ('a' - 'A');
Packit 40b132
    }
Packit 40b132
Packit 40b132
    if( ('a' <= f) && (f <= 'z') ) {
Packit 40b132
      f -= ('a' - 'A');
Packit 40b132
    }
Packit 40b132
Packit 40b132
    if( e != f ) {
Packit 40b132
      return PR_FALSE;
Packit 40b132
    }
Packit 40b132
Packit 40b132
    c++;
Packit 40b132
    d++;
Packit 40b132
Packit 40b132
    if( ' ' == *c ) {
Packit 40b132
      while( ' ' == *c ) {
Packit 40b132
        c++;
Packit 40b132
      }
Packit 40b132
      c--;
Packit 40b132
    }
Packit 40b132
Packit 40b132
    if( ' ' == *d ) {
Packit 40b132
      while( ' ' == *d ) {
Packit 40b132
        d++;
Packit 40b132
      }
Packit 40b132
      d--;
Packit 40b132
    }
Packit 40b132
  }
Packit 40b132
Packit 40b132
  while( ' ' == *c ) {
Packit 40b132
    c++;
Packit 40b132
  }
Packit 40b132
Packit 40b132
  while( ' ' == *d ) {
Packit 40b132
    d++;
Packit 40b132
  }
Packit 40b132
Packit 40b132
  if( *c == *d ) {
Packit 40b132
    /* And both '\0', btw */
Packit 40b132
    return PR_TRUE;
Packit 40b132
  } else {
Packit 40b132
    return PR_FALSE;
Packit 40b132
  }
Packit 40b132
}
Packit 40b132
Packit 40b132
/*
Packit 40b132
 * nssUTF8_Duplicate
Packit 40b132
 *
Packit 40b132
 * This routine duplicates the UTF8-encoded string pointed to by the
Packit 40b132
 * specified NSSUTF8 pointer.  If the optional arenaOpt argument is
Packit 40b132
 * not null, the memory required will be obtained from that arena;
Packit 40b132
 * otherwise, the memory required will be obtained from the heap.
Packit 40b132
 * A pointer to the new string will be returned.  In case of error,
Packit 40b132
 * an error will be placed on the error stack and NULL will be 
Packit 40b132
 * returned.
Packit 40b132
 *
Packit 40b132
 * The error may be one of the following values:
Packit 40b132
 *  NSS_ERROR_INVALID_POINTER
Packit 40b132
 *  NSS_ERROR_INVALID_ARENA
Packit 40b132
 *  NSS_ERROR_NO_MEMORY
Packit 40b132
 */
Packit 40b132
Packit 40b132
NSS_IMPLEMENT NSSUTF8 *
Packit 40b132
nssUTF8_Duplicate
Packit 40b132
(
Packit 40b132
  const NSSUTF8 *s,
Packit 40b132
  NSSArena *arenaOpt
Packit 40b132
)
Packit 40b132
{
Packit 40b132
  NSSUTF8 *rv;
Packit 40b132
  PRUint32 len;
Packit 40b132
Packit 40b132
#ifdef NSSDEBUG
Packit 40b132
  if( (const NSSUTF8 *)NULL == s ) {
Packit 40b132
    nss_SetError(NSS_ERROR_INVALID_POINTER);
Packit 40b132
    return (NSSUTF8 *)NULL;
Packit 40b132
  }
Packit 40b132
Packit 40b132
  if( (NSSArena *)NULL != arenaOpt ) {
Packit 40b132
    if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
Packit 40b132
      return (NSSUTF8 *)NULL;
Packit 40b132
    }
Packit 40b132
  }
Packit 40b132
#endif /* NSSDEBUG */
Packit 40b132
Packit 40b132
  len = PL_strlen((const char *)s);
Packit 40b132
#ifdef PEDANTIC
Packit 40b132
  if( '\0' != ((const char *)s)[ len ] ) {
Packit 40b132
    /* must have wrapped, e.g., too big for PRUint32 */
Packit 40b132
    nss_SetError(NSS_ERROR_NO_MEMORY);
Packit 40b132
    return (NSSUTF8 *)NULL;
Packit 40b132
  }
Packit 40b132
#endif /* PEDANTIC */
Packit 40b132
  len++; /* zero termination */
Packit 40b132
Packit 40b132
  rv = nss_ZAlloc(arenaOpt, len);
Packit 40b132
  if( (void *)NULL == rv ) {
Packit 40b132
    return (NSSUTF8 *)NULL;
Packit 40b132
  }
Packit 40b132
Packit 40b132
  (void)nsslibc_memcpy(rv, s, len);
Packit 40b132
  return rv;
Packit 40b132
}
Packit 40b132
Packit 40b132
/*
Packit 40b132
 * nssUTF8_Size
Packit 40b132
 *
Packit 40b132
 * This routine returns the length in bytes (including the terminating
Packit 40b132
 * null) of the UTF8-encoded string pointed to by the specified
Packit 40b132
 * NSSUTF8 pointer.  Zero is returned on error.
Packit 40b132
 *
Packit 40b132
 * The error may be one of the following values:
Packit 40b132
 *  NSS_ERROR_INVALID_POINTER
Packit 40b132
 *  NSS_ERROR_VALUE_TOO_LARGE
Packit 40b132
 *
Packit 40b132
 * Return value:
Packit 40b132
 *  0 on error
Packit 40b132
 *  nonzero length of the string.
Packit 40b132
 */
Packit 40b132
Packit 40b132
NSS_IMPLEMENT PRUint32
Packit 40b132
nssUTF8_Size
Packit 40b132
(
Packit 40b132
  const NSSUTF8 *s,
Packit 40b132
  PRStatus *statusOpt
Packit 40b132
)
Packit 40b132
{
Packit 40b132
  PRUint32 sv;
Packit 40b132
Packit 40b132
#ifdef NSSDEBUG
Packit 40b132
  if( (const NSSUTF8 *)NULL == s ) {
Packit 40b132
    nss_SetError(NSS_ERROR_INVALID_POINTER);
Packit 40b132
    if( (PRStatus *)NULL != statusOpt ) {
Packit 40b132
      *statusOpt = PR_FAILURE;
Packit 40b132
    }
Packit 40b132
    return 0;
Packit 40b132
  }
Packit 40b132
#endif /* NSSDEBUG */
Packit 40b132
Packit 40b132
  sv = PL_strlen((const char *)s) + 1;
Packit 40b132
#ifdef PEDANTIC
Packit 40b132
  if( '\0' != ((const char *)s)[ sv-1 ] ) {
Packit 40b132
    /* wrapped */
Packit 40b132
    nss_SetError(NSS_ERROR_VALUE_TOO_LARGE);
Packit 40b132
    if( (PRStatus *)NULL != statusOpt ) {
Packit 40b132
      *statusOpt = PR_FAILURE;
Packit 40b132
    }
Packit 40b132
    return 0;
Packit 40b132
  }
Packit 40b132
#endif /* PEDANTIC */
Packit 40b132
Packit 40b132
  if( (PRStatus *)NULL != statusOpt ) {
Packit 40b132
    *statusOpt = PR_SUCCESS;
Packit 40b132
  }
Packit 40b132
Packit 40b132
  return sv;
Packit 40b132
}
Packit 40b132
Packit 40b132
/*
Packit 40b132
 * nssUTF8_Length
Packit 40b132
 *
Packit 40b132
 * This routine returns the length in characters (not including the
Packit 40b132
 * terminating null) of the UTF8-encoded string pointed to by the
Packit 40b132
 * specified NSSUTF8 pointer.
Packit 40b132
 *
Packit 40b132
 * The error may be one of the following values:
Packit 40b132
 *  NSS_ERROR_INVALID_POINTER
Packit 40b132
 *  NSS_ERROR_VALUE_TOO_LARGE
Packit 40b132
 *  NSS_ERROR_INVALID_STRING
Packit 40b132
 *
Packit 40b132
 * Return value:
Packit 40b132
 *  length of the string (which may be zero)
Packit 40b132
 *  0 on error
Packit 40b132
 */
Packit 40b132
Packit 40b132
NSS_IMPLEMENT PRUint32
Packit 40b132
nssUTF8_Length
Packit 40b132
(
Packit 40b132
  const NSSUTF8 *s,
Packit 40b132
  PRStatus *statusOpt
Packit 40b132
)
Packit 40b132
{
Packit 40b132
  PRUint32 l = 0;
Packit 40b132
  const PRUint8 *c = (const PRUint8 *)s;
Packit 40b132
Packit 40b132
#ifdef NSSDEBUG
Packit 40b132
  if( (const NSSUTF8 *)NULL == s ) {
Packit 40b132
    nss_SetError(NSS_ERROR_INVALID_POINTER);
Packit 40b132
    goto loser;
Packit 40b132
  }
Packit 40b132
#endif /* NSSDEBUG */
Packit 40b132
Packit 40b132
  /*
Packit 40b132
   * From RFC 2044:
Packit 40b132
   *
Packit 40b132
   * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
Packit 40b132
   * 0000 0000-0000 007F   0xxxxxxx
Packit 40b132
   * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
Packit 40b132
   * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
Packit 40b132
   * 0001 0000-001F FFFF   11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
Packit 40b132
   * 0020 0000-03FF FFFF   111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
Packit 40b132
   * 0400 0000-7FFF FFFF   1111110x 10xxxxxx ... 10xxxxxx
Packit 40b132
   */  
Packit 40b132
Packit 40b132
  while( 0 != *c ) {
Packit 40b132
    PRUint32 incr;
Packit 40b132
    if( (*c & 0x80) == 0 ) {
Packit 40b132
      incr = 1;
Packit 40b132
    } else if( (*c & 0xE0) == 0xC0 ) {
Packit 40b132
      incr = 2;
Packit 40b132
    } else if( (*c & 0xF0) == 0xE0 ) {
Packit 40b132
      incr = 3;
Packit 40b132
    } else if( (*c & 0xF8) == 0xF0 ) {
Packit 40b132
      incr = 4;
Packit 40b132
    } else if( (*c & 0xFC) == 0xF8 ) {
Packit 40b132
      incr = 5;
Packit 40b132
    } else if( (*c & 0xFE) == 0xFC ) {
Packit 40b132
      incr = 6;
Packit 40b132
    } else {
Packit 40b132
      nss_SetError(NSS_ERROR_INVALID_STRING);
Packit 40b132
      goto loser;
Packit 40b132
    }
Packit 40b132
Packit 40b132
    l += incr;
Packit 40b132
Packit 40b132
#ifdef PEDANTIC
Packit 40b132
    if( l < incr ) {
Packit 40b132
      /* Wrapped-- too big */
Packit 40b132
      nss_SetError(NSS_ERROR_VALUE_TOO_LARGE);
Packit 40b132
      goto loser;
Packit 40b132
    }
Packit 40b132
Packit 40b132
    {
Packit 40b132
      PRUint8 *d;
Packit 40b132
      for( d = &c[1]; d < &c[incr]; d++ ) {
Packit 40b132
        if( (*d & 0xC0) != 0xF0 ) {
Packit 40b132
          nss_SetError(NSS_ERROR_INVALID_STRING);
Packit 40b132
          goto loser;
Packit 40b132
        }
Packit 40b132
      }
Packit 40b132
    }
Packit 40b132
#endif /* PEDANTIC */
Packit 40b132
Packit 40b132
    c += incr;
Packit 40b132
  }
Packit 40b132
Packit 40b132
  if( (PRStatus *)NULL != statusOpt ) {
Packit 40b132
    *statusOpt = PR_SUCCESS;
Packit 40b132
  }
Packit 40b132
Packit 40b132
  return l;
Packit 40b132
Packit 40b132
 loser:
Packit 40b132
  if( (PRStatus *)NULL != statusOpt ) {
Packit 40b132
    *statusOpt = PR_FAILURE;
Packit 40b132
  }
Packit 40b132
Packit 40b132
  return 0;
Packit 40b132
}
Packit 40b132
Packit 40b132
Packit 40b132
/*
Packit 40b132
 * nssUTF8_Create
Packit 40b132
 *
Packit 40b132
 * This routine creates a UTF8 string from a string in some other
Packit 40b132
 * format.  Some types of string may include embedded null characters,
Packit 40b132
 * so for them the length parameter must be used.  For string types
Packit 40b132
 * that are null-terminated, the length parameter is optional; if it
Packit 40b132
 * is zero, it will be ignored.  If the optional arena argument is
Packit 40b132
 * non-null, the memory used for the new string will be obtained from
Packit 40b132
 * that arena, otherwise it will be obtained from the heap.  This
Packit 40b132
 * routine may return NULL upon error, in which case it will have
Packit 40b132
 * placed an error on the error stack.
Packit 40b132
 *
Packit 40b132
 * The error may be one of the following:
Packit 40b132
 *  NSS_ERROR_INVALID_POINTER
Packit 40b132
 *  NSS_ERROR_NO_MEMORY
Packit 40b132
 *  NSS_ERROR_UNSUPPORTED_TYPE
Packit 40b132
 *
Packit 40b132
 * Return value:
Packit 40b132
 *  NULL upon error
Packit 40b132
 *  A non-null pointer to a new UTF8 string otherwise
Packit 40b132
 */
Packit 40b132
Packit 40b132
extern const NSSError NSS_ERROR_INTERNAL_ERROR; /* XXX fgmr */
Packit 40b132
Packit 40b132
NSS_IMPLEMENT NSSUTF8 *
Packit 40b132
nssUTF8_Create
Packit 40b132
(
Packit 40b132
  NSSArena *arenaOpt,
Packit 40b132
  nssStringType type,
Packit 40b132
  const void *inputString,
Packit 40b132
  PRUint32 size /* in bytes, not characters */
Packit 40b132
)
Packit 40b132
{
Packit 40b132
  NSSUTF8 *rv = NULL;
Packit 40b132
Packit 40b132
#ifdef NSSDEBUG
Packit 40b132
  if( (NSSArena *)NULL != arenaOpt ) {
Packit 40b132
    if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
Packit 40b132
      return (NSSUTF8 *)NULL;
Packit 40b132
    }
Packit 40b132
  }
Packit 40b132
Packit 40b132
  if( (const void *)NULL == inputString ) {
Packit 40b132
    nss_SetError(NSS_ERROR_INVALID_POINTER);
Packit 40b132
    return (NSSUTF8 *)NULL;
Packit 40b132
  }
Packit 40b132
#endif /* NSSDEBUG */
Packit 40b132
Packit 40b132
  switch( type ) {
Packit 40b132
  case nssStringType_DirectoryString:
Packit 40b132
    /* This is a composite type requiring BER */
Packit 40b132
    nss_SetError(NSS_ERROR_UNSUPPORTED_TYPE);
Packit 40b132
    break;
Packit 40b132
  case nssStringType_TeletexString:
Packit 40b132
    /*
Packit 40b132
     * draft-ietf-pkix-ipki-part1-11 says in part:
Packit 40b132
     *
Packit 40b132
     * In addition, many legacy implementations support names encoded 
Packit 40b132
     * in the ISO 8859-1 character set (Latin1String) but tag them as 
Packit 40b132
     * TeletexString.  The Latin1String includes characters used in 
Packit 40b132
     * Western European countries which are not part of the 
Packit 40b132
     * TeletexString charcter set.  Implementations that process 
Packit 40b132
     * TeletexString SHOULD be prepared to handle the entire ISO 
Packit 40b132
     * 8859-1 character set.[ISO 8859-1].
Packit 40b132
     */
Packit 40b132
    nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
Packit 40b132
    break;
Packit 40b132
  case nssStringType_PrintableString:
Packit 40b132
    /*
Packit 40b132
     * PrintableString consists of A-Za-z0-9 ,()+,-./:=?
Packit 40b132
     * This is a subset of ASCII, which is a subset of UTF8.
Packit 40b132
     * So we can just duplicate the string over.
Packit 40b132
     */
Packit 40b132
Packit 40b132
    if( 0 == size ) {
Packit 40b132
      rv = nssUTF8_Duplicate((const NSSUTF8 *)inputString, arenaOpt);
Packit 40b132
    } else {
Packit 40b132
      rv = nss_ZAlloc(arenaOpt, size+1);
Packit 40b132
      if( (NSSUTF8 *)NULL == rv ) {
Packit 40b132
        return (NSSUTF8 *)NULL;
Packit 40b132
      }
Packit 40b132
Packit 40b132
      (void)nsslibc_memcpy(rv, inputString, size);
Packit 40b132
    }
Packit 40b132
Packit 40b132
    break;
Packit 40b132
  case nssStringType_UniversalString:
Packit 40b132
    /* 4-byte unicode */
Packit 40b132
    nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
Packit 40b132
    break;
Packit 40b132
  case nssStringType_BMPString:
Packit 40b132
    /* Base Multilingual Plane of Unicode */
Packit 40b132
    nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
Packit 40b132
    break;
Packit 40b132
  case nssStringType_UTF8String:
Packit 40b132
    if( 0 == size ) {
Packit 40b132
      rv = nssUTF8_Duplicate((const NSSUTF8 *)inputString, arenaOpt);
Packit 40b132
    } else {
Packit 40b132
      rv = nss_ZAlloc(arenaOpt, size+1);
Packit 40b132
      if( (NSSUTF8 *)NULL == rv ) {
Packit 40b132
        return (NSSUTF8 *)NULL;
Packit 40b132
      }
Packit 40b132
Packit 40b132
      (void)nsslibc_memcpy(rv, inputString, size);
Packit 40b132
    }
Packit 40b132
Packit 40b132
    break;
Packit 40b132
  case nssStringType_PHGString:
Packit 40b132
    /* 
Packit 40b132
     * PHGString is an IA5String (with case-insensitive comparisons).
Packit 40b132
     * IA5 is ~almost~ ascii; ascii has dollar-sign where IA5 has
Packit 40b132
     * currency symbol.
Packit 40b132
     */
Packit 40b132
    nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
Packit 40b132
    break;
Packit 40b132
  case nssStringType_GeneralString:
Packit 40b132
    nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
Packit 40b132
    break;
Packit 40b132
  default:
Packit 40b132
    nss_SetError(NSS_ERROR_UNSUPPORTED_TYPE);
Packit 40b132
    break;
Packit 40b132
  }
Packit 40b132
Packit 40b132
  return rv;
Packit 40b132
}
Packit 40b132
Packit 40b132
NSS_IMPLEMENT NSSItem *
Packit 40b132
nssUTF8_GetEncoding
Packit 40b132
(
Packit 40b132
  NSSArena *arenaOpt,
Packit 40b132
  NSSItem *rvOpt,
Packit 40b132
  nssStringType type,
Packit 40b132
  NSSUTF8 *string
Packit 40b132
)
Packit 40b132
{
Packit 40b132
  NSSItem *rv = (NSSItem *)NULL;
Packit 40b132
  PRStatus status = PR_SUCCESS;
Packit 40b132
Packit 40b132
#ifdef NSSDEBUG
Packit 40b132
  if( (NSSArena *)NULL != arenaOpt ) {
Packit 40b132
    if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
Packit 40b132
      return (NSSItem *)NULL;
Packit 40b132
    }
Packit 40b132
  }
Packit 40b132
Packit 40b132
  if( (NSSUTF8 *)NULL == string ) {
Packit 40b132
    nss_SetError(NSS_ERROR_INVALID_POINTER);
Packit 40b132
    return (NSSItem *)NULL;
Packit 40b132
  }
Packit 40b132
#endif /* NSSDEBUG */
Packit 40b132
Packit 40b132
  switch( type ) {
Packit 40b132
  case nssStringType_DirectoryString:
Packit 40b132
    nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
Packit 40b132
    break;
Packit 40b132
  case nssStringType_TeletexString:
Packit 40b132
    nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
Packit 40b132
    break;
Packit 40b132
  case nssStringType_PrintableString:
Packit 40b132
    nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
Packit 40b132
    break;
Packit 40b132
  case nssStringType_UniversalString:
Packit 40b132
    nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
Packit 40b132
    break;
Packit 40b132
  case nssStringType_BMPString:
Packit 40b132
    nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
Packit 40b132
    break;
Packit 40b132
  case nssStringType_UTF8String:
Packit 40b132
    {
Packit 40b132
      NSSUTF8 *dup = nssUTF8_Duplicate(string, arenaOpt);
Packit 40b132
      if( (NSSUTF8 *)NULL == dup ) {
Packit 40b132
        return (NSSItem *)NULL;
Packit 40b132
      }
Packit 40b132
Packit 40b132
      if( (NSSItem *)NULL == rvOpt ) {
Packit 40b132
        rv = nss_ZNEW(arenaOpt, NSSItem);
Packit 40b132
        if( (NSSItem *)NULL == rv ) {
Packit 40b132
          (void)nss_ZFreeIf(dup);
Packit 40b132
          return (NSSItem *)NULL;
Packit 40b132
        }
Packit 40b132
      } else {
Packit 40b132
        rv = rvOpt;
Packit 40b132
      }
Packit 40b132
Packit 40b132
      rv->data = dup;
Packit 40b132
      dup = (NSSUTF8 *)NULL;
Packit 40b132
      rv->size = nssUTF8_Size(rv->data, &status);
Packit 40b132
      if( (0 == rv->size) && (PR_SUCCESS != status) ) {
Packit 40b132
        if( (NSSItem *)NULL == rvOpt ) {
Packit 40b132
          (void)nss_ZFreeIf(rv);
Packit 40b132
        }
Packit 40b132
        return (NSSItem *)NULL;
Packit 40b132
      }
Packit 40b132
    }
Packit 40b132
    break;
Packit 40b132
  case nssStringType_PHGString:
Packit 40b132
    nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
Packit 40b132
    break;
Packit 40b132
  default:
Packit 40b132
    nss_SetError(NSS_ERROR_UNSUPPORTED_TYPE);
Packit 40b132
    break;
Packit 40b132
  }
Packit 40b132
Packit 40b132
  return rv;
Packit 40b132
}
Packit 40b132
Packit 40b132
/*
Packit 40b132
 * nssUTF8_CopyIntoFixedBuffer
Packit 40b132
 *
Packit 40b132
 * This will copy a UTF8 string into a fixed-length buffer, making 
Packit 40b132
 * sure that the all characters are valid.  Any remaining space will
Packit 40b132
 * be padded with the specified ASCII character, typically either 
Packit 40b132
 * null or space.
Packit 40b132
 *
Packit 40b132
 * Blah, blah, blah.
Packit 40b132
 */
Packit 40b132
Packit 40b132
NSS_IMPLEMENT PRStatus
Packit 40b132
nssUTF8_CopyIntoFixedBuffer
Packit 40b132
(
Packit 40b132
  NSSUTF8 *string,
Packit 40b132
  char *buffer,
Packit 40b132
  PRUint32 bufferSize,
Packit 40b132
  char pad
Packit 40b132
)
Packit 40b132
{
Packit 40b132
  PRUint32 stringSize = 0;
Packit 40b132
Packit 40b132
#ifdef NSSDEBUG
Packit 40b132
  if( (char *)NULL == buffer ) {
Packit 40b132
    nss_SetError(NSS_ERROR_INVALID_POINTER);
Packit 40b132
    return PR_FALSE;
Packit 40b132
  }
Packit 40b132
Packit 40b132
  if( 0 == bufferSize ) {
Packit 40b132
    nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
Packit 40b132
    return PR_FALSE;
Packit 40b132
  }
Packit 40b132
Packit 40b132
  if( (pad & 0x80) != 0x00 ) {
Packit 40b132
    nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
Packit 40b132
    return PR_FALSE;
Packit 40b132
  }
Packit 40b132
#endif /* NSSDEBUG */
Packit 40b132
Packit 40b132
  if( (NSSUTF8 *)NULL == string ) {
Packit 40b132
    string = (NSSUTF8 *) "";
Packit 40b132
  }
Packit 40b132
Packit 40b132
  stringSize = nssUTF8_Size(string, (PRStatus *)NULL);
Packit 40b132
  stringSize--; /* don't count the trailing null */
Packit 40b132
  if( stringSize > bufferSize ) {
Packit 40b132
    PRUint32 bs = bufferSize;
Packit 40b132
    (void)nsslibc_memcpy(buffer, string, bufferSize);
Packit 40b132
    
Packit 40b132
    if( (            ((buffer[ bs-1 ] & 0x80) == 0x00)) ||
Packit 40b132
        ((bs > 1) && ((buffer[ bs-2 ] & 0xE0) == 0xC0)) ||
Packit 40b132
        ((bs > 2) && ((buffer[ bs-3 ] & 0xF0) == 0xE0)) ||
Packit 40b132
        ((bs > 3) && ((buffer[ bs-4 ] & 0xF8) == 0xF0)) ||
Packit 40b132
        ((bs > 4) && ((buffer[ bs-5 ] & 0xFC) == 0xF8)) ||
Packit 40b132
        ((bs > 5) && ((buffer[ bs-6 ] & 0xFE) == 0xFC)) ) {
Packit 40b132
      /* It fit exactly */
Packit 40b132
      return PR_SUCCESS;
Packit 40b132
    }
Packit 40b132
Packit 40b132
    /* Too long.  We have to trim the last character */
Packit 40b132
    for( /*bs*/; bs != 0; bs-- ) {
Packit 40b132
      if( (buffer[bs-1] & 0xC0) != 0x80 ) {
Packit 40b132
        buffer[bs-1] = pad;
Packit 40b132
        break;
Packit 40b132
      } else {
Packit 40b132
        buffer[bs-1] = pad;
Packit 40b132
      }
Packit 40b132
    }      
Packit 40b132
  } else {
Packit 40b132
    (void)nsslibc_memset(buffer, pad, bufferSize);
Packit 40b132
    (void)nsslibc_memcpy(buffer, string, stringSize);
Packit 40b132
  }
Packit 40b132
Packit 40b132
  return PR_SUCCESS;
Packit 40b132
}
Packit 40b132
Packit 40b132
/*
Packit 40b132
 * nssUTF8_Equal
Packit 40b132
 *
Packit 40b132
 */
Packit 40b132
Packit 40b132
NSS_IMPLEMENT PRBool
Packit 40b132
nssUTF8_Equal
Packit 40b132
(
Packit 40b132
  const NSSUTF8 *a,
Packit 40b132
  const NSSUTF8 *b,
Packit 40b132
  PRStatus *statusOpt
Packit 40b132
)
Packit 40b132
{
Packit 40b132
  PRUint32 la, lb;
Packit 40b132
Packit 40b132
#ifdef NSSDEBUG
Packit 40b132
  if( ((const NSSUTF8 *)NULL == a) ||
Packit 40b132
      ((const NSSUTF8 *)NULL == b) ) {
Packit 40b132
    nss_SetError(NSS_ERROR_INVALID_POINTER);
Packit 40b132
    if( (PRStatus *)NULL != statusOpt ) {
Packit 40b132
      *statusOpt = PR_FAILURE;
Packit 40b132
    }
Packit 40b132
    return PR_FALSE;
Packit 40b132
  }
Packit 40b132
#endif /* NSSDEBUG */
Packit 40b132
Packit 40b132
  la = nssUTF8_Size(a, statusOpt);
Packit 40b132
  if( 0 == la ) {
Packit 40b132
    return PR_FALSE;
Packit 40b132
  }
Packit 40b132
Packit 40b132
  lb = nssUTF8_Size(b, statusOpt);
Packit 40b132
  if( 0 == lb ) {
Packit 40b132
    return PR_FALSE;
Packit 40b132
  }
Packit 40b132
Packit 40b132
  if( la != lb ) {
Packit 40b132
    return PR_FALSE;
Packit 40b132
  }
Packit 40b132
Packit 40b132
  return nsslibc_memequal(a, b, la, statusOpt);
Packit 40b132
}