utf8.c
上传用户:lyxiangda
上传日期:2007-01-12
资源大小:3042k
文件大小:18k
源码类别:

CA认证

开发平台:

WINDOWS

  1. /* 
  2.  * The contents of this file are subject to the Mozilla Public
  3.  * License Version 1.1 (the "License"); you may not use this file
  4.  * except in compliance with the License. You may obtain a copy of
  5.  * the License at http://www.mozilla.org/MPL/
  6.  * 
  7.  * Software distributed under the License is distributed on an "AS
  8.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  9.  * implied. See the License for the specific language governing
  10.  * rights and limitations under the License.
  11.  * 
  12.  * The Original Code is the Netscape security libraries.
  13.  * 
  14.  * The Initial Developer of the Original Code is Netscape
  15.  * Communications Corporation.  Portions created by Netscape are 
  16.  * Copyright (C) 1994-2000 Netscape Communications Corporation.  All
  17.  * Rights Reserved.
  18.  * 
  19.  * Contributor(s):
  20.  * 
  21.  * Alternatively, the contents of this file may be used under the
  22.  * terms of the GNU General Public License Version 2 or later (the
  23.  * "GPL"), in which case the provisions of the GPL are applicable 
  24.  * instead of those above.  If you wish to allow use of your 
  25.  * version of this file only under the terms of the GPL and not to
  26.  * allow others to use your version of this file under the MPL,
  27.  * indicate your decision by deleting the provisions above and
  28.  * replace them with the notice and other provisions required by
  29.  * the GPL.  If you do not delete the provisions above, a recipient
  30.  * may use your version of this file under either the MPL or the
  31.  * GPL.
  32.  */
  33. #ifdef DEBUG
  34. static const char CVS_ID[] = "@(#) $RCSfile: utf8.c,v $ $Revision: 1.3 $ $Date: 2000/05/12 18:43:28 $ $Name: NSS_3_1_1_RTM $";
  35. #endif /* DEBUG */
  36. /*
  37.  * utf8.c
  38.  *
  39.  * This file contains some additional utility routines required for
  40.  * handling UTF8 strings.
  41.  */
  42. #ifndef BASE_H
  43. #include "base.h"
  44. #endif /* BASE_H */
  45. #include "plstr.h"
  46. /*
  47.  * NOTES:
  48.  *
  49.  * There's an "is hex string" function in pki1/atav.c.  If we need
  50.  * it in more places, pull that one out.
  51.  */
  52. /*
  53.  * nssUTF8_CaseIgnoreMatch
  54.  * 
  55.  * Returns true if the two UTF8-encoded strings pointed to by the 
  56.  * two specified NSSUTF8 pointers differ only in typcase.
  57.  *
  58.  * The error may be one of the following values:
  59.  *  NSS_ERROR_INVALID_POINTER
  60.  *
  61.  * Return value:
  62.  *  PR_TRUE if the strings match, ignoring case
  63.  *  PR_FALSE if they don't
  64.  *  PR_FALSE upon error
  65.  */
  66. NSS_IMPLEMENT PRBool
  67. nssUTF8_CaseIgnoreMatch
  68. (
  69.   const NSSUTF8 *a,
  70.   const NSSUTF8 *b,
  71.   PRStatus *statusOpt
  72. )
  73. {
  74. #ifdef NSSDEBUG
  75.   if( ((const NSSUTF8 *)NULL == a) ||
  76.       ((const NSSUTF8 *)NULL == b) ) {
  77.     nss_SetError(NSS_ERROR_INVALID_POINTER);
  78.     if( (PRStatus *)NULL != statusOpt ) {
  79.       *statusOpt = PR_FAILURE;
  80.     }
  81.     return PR_FALSE;
  82.   }
  83. #endif /* NSSDEBUG */
  84.   if( (PRStatus *)NULL != statusOpt ) {
  85.     *statusOpt = PR_SUCCESS;
  86.   }
  87.   /*
  88.    * XXX fgmr
  89.    *
  90.    * This is, like, so wrong!
  91.    */
  92.   if( 0 == PL_strcasecmp((const char *)a, (const char *)b) ) {
  93.     return PR_TRUE;
  94.   } else {
  95.     return PR_FALSE;
  96.   }
  97. }
  98. /*
  99.  * nssUTF8_PrintableMatch
  100.  *
  101.  * Returns true if the two Printable strings pointed to by the 
  102.  * two specified NSSUTF8 pointers match when compared with the 
  103.  * rules for Printable String (leading and trailing spaces are 
  104.  * disregarded, extents of whitespace match irregardless of length, 
  105.  * and case is not significant), then PR_TRUE will be returned.
  106.  * Otherwise, PR_FALSE will be returned.  Upon failure, PR_FALSE
  107.  * will be returned.  If the optional statusOpt argument is not
  108.  * NULL, then PR_SUCCESS or PR_FAILURE will be stored in that
  109.  * location.
  110.  *
  111.  * The error may be one of the following values:
  112.  *  NSS_ERROR_INVALID_POINTER
  113.  *
  114.  * Return value:
  115.  *  PR_TRUE if the strings match, ignoring case
  116.  *  PR_FALSE if they don't
  117.  *  PR_FALSE upon error
  118.  */
  119. NSS_IMPLEMENT PRBool
  120. nssUTF8_PrintableMatch
  121. (
  122.   const NSSUTF8 *a,
  123.   const NSSUTF8 *b,
  124.   PRStatus *statusOpt
  125. )
  126. {
  127.   PRUint8 *c;
  128.   PRUint8 *d;
  129. #ifdef NSSDEBUG
  130.   if( ((const NSSUTF8 *)NULL == a) ||
  131.       ((const NSSUTF8 *)NULL == b) ) {
  132.     nss_SetError(NSS_ERROR_INVALID_POINTER);
  133.     if( (PRStatus *)NULL != statusOpt ) {
  134.       *statusOpt = PR_FAILURE;
  135.     }
  136.     return PR_FALSE;
  137.   }
  138. #endif /* NSSDEBUG */
  139.   if( (PRStatus *)NULL != statusOpt ) {
  140.     *statusOpt = PR_SUCCESS;
  141.   }
  142.   c = (PRUint8 *)a;
  143.   d = (PRUint8 *)b;
  144.   while( ' ' == *c ) {
  145.     c++;
  146.   }
  147.   while( ' ' == *d ) {
  148.     d++;
  149.   }
  150.   while( ('' != *c) && ('' != *d) ) {
  151.     PRUint8 e, f;
  152.     e = *c;
  153.     f = *d;
  154.     
  155.     if( ('a' <= e) && (e <= 'z') ) {
  156.       e -= ('a' - 'A');
  157.     }
  158.     if( ('a' <= f) && (f <= 'z') ) {
  159.       f -= ('a' - 'A');
  160.     }
  161.     if( e != f ) {
  162.       return PR_FALSE;
  163.     }
  164.     c++;
  165.     d++;
  166.     if( ' ' == *c ) {
  167.       while( ' ' == *c ) {
  168.         c++;
  169.       }
  170.       c--;
  171.     }
  172.     if( ' ' == *d ) {
  173.       while( ' ' == *d ) {
  174.         d++;
  175.       }
  176.       d--;
  177.     }
  178.   }
  179.   while( ' ' == *c ) {
  180.     c++;
  181.   }
  182.   while( ' ' == *d ) {
  183.     d++;
  184.   }
  185.   if( *c == *d ) {
  186.     /* And both '', btw */
  187.     return PR_TRUE;
  188.   } else {
  189.     return PR_FALSE;
  190.   }
  191. }
  192. /*
  193.  * nssUTF8_Duplicate
  194.  *
  195.  * This routine duplicates the UTF8-encoded string pointed to by the
  196.  * specified NSSUTF8 pointer.  If the optional arenaOpt argument is
  197.  * not null, the memory required will be obtained from that arena;
  198.  * otherwise, the memory required will be obtained from the heap.
  199.  * A pointer to the new string will be returned.  In case of error,
  200.  * an error will be placed on the error stack and NULL will be 
  201.  * returned.
  202.  *
  203.  * The error may be one of the following values:
  204.  *  NSS_ERROR_INVALID_POINTER
  205.  *  NSS_ERROR_INVALID_ARENA
  206.  *  NSS_ERROR_NO_MEMORY
  207.  */
  208. NSS_IMPLEMENT NSSUTF8 *
  209. nssUTF8_Duplicate
  210. (
  211.   const NSSUTF8 *s,
  212.   NSSArena *arenaOpt
  213. )
  214. {
  215.   NSSUTF8 *rv;
  216.   PRUint32 len;
  217. #ifdef NSSDEBUG
  218.   if( (const NSSUTF8 *)NULL == s ) {
  219.     nss_SetError(NSS_ERROR_INVALID_POINTER);
  220.     return (NSSUTF8 *)NULL;
  221.   }
  222.   if( (NSSArena *)NULL != arenaOpt ) {
  223.     if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
  224.       return (NSSUTF8 *)NULL;
  225.     }
  226.   }
  227. #endif /* NSSDEBUG */
  228.   len = PL_strlen((const char *)s);
  229. #ifdef PEDANTIC
  230.   if( '' != ((const char *)s)[ len ] ) {
  231.     /* must have wrapped, e.g., too big for PRUint32 */
  232.     nss_SetError(NSS_ERROR_NO_MEMORY);
  233.     return (NSSUTF8 *)NULL;
  234.   }
  235. #endif /* PEDANTIC */
  236.   len++; /* zero termination */
  237.   rv = nss_ZAlloc(arenaOpt, len);
  238.   if( (void *)NULL == rv ) {
  239.     return (NSSUTF8 *)NULL;
  240.   }
  241.   (void)nsslibc_memcpy(rv, s, len);
  242.   return rv;
  243. }
  244. /*
  245.  * nssUTF8_Size
  246.  *
  247.  * This routine returns the length in bytes (including the terminating
  248.  * null) of the UTF8-encoded string pointed to by the specified
  249.  * NSSUTF8 pointer.  Zero is returned on error.
  250.  *
  251.  * The error may be one of the following values:
  252.  *  NSS_ERROR_INVALID_POINTER
  253.  *  NSS_ERROR_VALUE_TOO_LARGE
  254.  *
  255.  * Return value:
  256.  *  0 on error
  257.  *  nonzero length of the string.
  258.  */
  259. NSS_IMPLEMENT PRUint32
  260. nssUTF8_Size
  261. (
  262.   const NSSUTF8 *s,
  263.   PRStatus *statusOpt
  264. )
  265. {
  266.   PRUint32 sv;
  267. #ifdef NSSDEBUG
  268.   if( (const NSSUTF8 *)NULL == s ) {
  269.     nss_SetError(NSS_ERROR_INVALID_POINTER);
  270.     if( (PRStatus *)NULL != statusOpt ) {
  271.       *statusOpt = PR_FAILURE;
  272.     }
  273.     return 0;
  274.   }
  275. #endif /* NSSDEBUG */
  276.   sv = PL_strlen((const char *)s) + 1;
  277. #ifdef PEDANTIC
  278.   if( '' != ((const char *)s)[ sv-1 ] ) {
  279.     /* wrapped */
  280.     nss_SetError(NSS_ERROR_VALUE_TOO_LARGE);
  281.     if( (PRStatus *)NULL != statusOpt ) {
  282.       *statusOpt = PR_FAILURE;
  283.     }
  284.     return 0;
  285.   }
  286. #endif /* PEDANTIC */
  287.   if( (PRStatus *)NULL != statusOpt ) {
  288.     *statusOpt = PR_SUCCESS;
  289.   }
  290.   return sv;
  291. }
  292. /*
  293.  * nssUTF8_Length
  294.  *
  295.  * This routine returns the length in characters (not including the
  296.  * terminating null) of the UTF8-encoded string pointed to by the
  297.  * specified NSSUTF8 pointer.
  298.  *
  299.  * The error may be one of the following values:
  300.  *  NSS_ERROR_INVALID_POINTER
  301.  *  NSS_ERROR_VALUE_TOO_LARGE
  302.  *  NSS_ERROR_INVALID_STRING
  303.  *
  304.  * Return value:
  305.  *  length of the string (which may be zero)
  306.  *  0 on error
  307.  */
  308. NSS_IMPLEMENT PRUint32
  309. nssUTF8_Length
  310. (
  311.   const NSSUTF8 *s,
  312.   PRStatus *statusOpt
  313. )
  314. {
  315.   PRUint32 l = 0;
  316.   const PRUint8 *c = (const PRUint8 *)s;
  317. #ifdef NSSDEBUG
  318.   if( (const NSSUTF8 *)NULL == s ) {
  319.     nss_SetError(NSS_ERROR_INVALID_POINTER);
  320.     goto loser;
  321.   }
  322. #endif /* NSSDEBUG */
  323.   /*
  324.    * From RFC 2044:
  325.    *
  326.    * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
  327.    * 0000 0000-0000 007F   0xxxxxxx
  328.    * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
  329.    * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
  330.    * 0001 0000-001F FFFF   11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
  331.    * 0020 0000-03FF FFFF   111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
  332.    * 0400 0000-7FFF FFFF   1111110x 10xxxxxx ... 10xxxxxx
  333.    */  
  334.   while( 0 != *c ) {
  335.     PRUint32 incr;
  336.     if( (*c & 0x80) == 0 ) {
  337.       incr = 1;
  338.     } else if( (*c & 0xE0) == 0xC0 ) {
  339.       incr = 2;
  340.     } else if( (*c & 0xF0) == 0xE0 ) {
  341.       incr = 3;
  342.     } else if( (*c & 0xF8) == 0xF0 ) {
  343.       incr = 4;
  344.     } else if( (*c & 0xFC) == 0xF8 ) {
  345.       incr = 5;
  346.     } else if( (*c & 0xFE) == 0xFC ) {
  347.       incr = 6;
  348.     } else {
  349.       nss_SetError(NSS_ERROR_INVALID_STRING);
  350.       goto loser;
  351.     }
  352.     l += incr;
  353. #ifdef PEDANTIC
  354.     if( l < incr ) {
  355.       /* Wrapped-- too big */
  356.       nss_SetError(NSS_ERROR_VALUE_TOO_LARGE);
  357.       goto loser;
  358.     }
  359.     {
  360.       PRUint8 *d;
  361.       for( d = &c[1]; d < &c[incr]; d++ ) {
  362.         if( (*d & 0xC0) != 0xF0 ) {
  363.           nss_SetError(NSS_ERROR_INVALID_STRING);
  364.           goto loser;
  365.         }
  366.       }
  367.     }
  368. #endif /* PEDANTIC */
  369.     c += incr;
  370.   }
  371.   if( (PRStatus *)NULL != statusOpt ) {
  372.     *statusOpt = PR_SUCCESS;
  373.   }
  374.   return l;
  375.  loser:
  376.   if( (PRStatus *)NULL != statusOpt ) {
  377.     *statusOpt = PR_FAILURE;
  378.   }
  379.   return 0;
  380. }
  381. /*
  382.  * nssUTF8_Create
  383.  *
  384.  * This routine creates a UTF8 string from a string in some other
  385.  * format.  Some types of string may include embedded null characters,
  386.  * so for them the length parameter must be used.  For string types
  387.  * that are null-terminated, the length parameter is optional; if it
  388.  * is zero, it will be ignored.  If the optional arena argument is
  389.  * non-null, the memory used for the new string will be obtained from
  390.  * that arena, otherwise it will be obtained from the heap.  This
  391.  * routine may return NULL upon error, in which case it will have
  392.  * placed an error on the error stack.
  393.  *
  394.  * The error may be one of the following:
  395.  *  NSS_ERROR_INVALID_POINTER
  396.  *  NSS_ERROR_NO_MEMORY
  397.  *  NSS_ERROR_UNSUPPORTED_TYPE
  398.  *
  399.  * Return value:
  400.  *  NULL upon error
  401.  *  A non-null pointer to a new UTF8 string otherwise
  402.  */
  403. extern const NSSError NSS_ERROR_INTERNAL_ERROR; /* XXX fgmr */
  404. NSS_IMPLEMENT NSSUTF8 *
  405. nssUTF8_Create
  406. (
  407.   NSSArena *arenaOpt,
  408.   nssStringType type,
  409.   const void *inputString,
  410.   PRUint32 size /* in bytes, not characters */
  411. )
  412. {
  413.   NSSUTF8 *rv = NULL;
  414. #ifdef NSSDEBUG
  415.   if( (NSSArena *)NULL != arenaOpt ) {
  416.     if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
  417.       return (NSSUTF8 *)NULL;
  418.     }
  419.   }
  420.   if( (const void *)NULL == inputString ) {
  421.     nss_SetError(NSS_ERROR_INVALID_POINTER);
  422.     return (NSSUTF8 *)NULL;
  423.   }
  424. #endif /* NSSDEBUG */
  425.   switch( type ) {
  426.   case nssStringType_DirectoryString:
  427.     /* This is a composite type requiring BER */
  428.     nss_SetError(NSS_ERROR_UNSUPPORTED_TYPE);
  429.     break;
  430.   case nssStringType_TeletexString:
  431.     /*
  432.      * draft-ietf-pkix-ipki-part1-11 says in part:
  433.      *
  434.      * In addition, many legacy implementations support names encoded 
  435.      * in the ISO 8859-1 character set (Latin1String) but tag them as 
  436.      * TeletexString.  The Latin1String includes characters used in 
  437.      * Western European countries which are not part of the 
  438.      * TeletexString charcter set.  Implementations that process 
  439.      * TeletexString SHOULD be prepared to handle the entire ISO 
  440.      * 8859-1 character set.[ISO 8859-1].
  441.      */
  442.     nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
  443.     break;
  444.   case nssStringType_PrintableString:
  445.     /*
  446.      * PrintableString consists of A-Za-z0-9 ,()+,-./:=?
  447.      * This is a subset of ASCII, which is a subset of UTF8.
  448.      * So we can just duplicate the string over.
  449.      */
  450.     if( 0 == size ) {
  451.       rv = nssUTF8_Duplicate((const NSSUTF8 *)inputString, arenaOpt);
  452.     } else {
  453.       rv = nss_ZAlloc(arenaOpt, size+1);
  454.       if( (NSSUTF8 *)NULL == rv ) {
  455.         return (NSSUTF8 *)NULL;
  456.       }
  457.       (void)nsslibc_memcpy(rv, inputString, size);
  458.     }
  459.     break;
  460.   case nssStringType_UniversalString:
  461.     /* 4-byte unicode */
  462.     nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
  463.     break;
  464.   case nssStringType_BMPString:
  465.     /* Base Multilingual Plane of Unicode */
  466.     nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
  467.     break;
  468.   case nssStringType_UTF8String:
  469.     if( 0 == size ) {
  470.       rv = nssUTF8_Duplicate((const NSSUTF8 *)inputString, arenaOpt);
  471.     } else {
  472.       rv = nss_ZAlloc(arenaOpt, size+1);
  473.       if( (NSSUTF8 *)NULL == rv ) {
  474.         return (NSSUTF8 *)NULL;
  475.       }
  476.       (void)nsslibc_memcpy(rv, inputString, size);
  477.     }
  478.     break;
  479.   case nssStringType_PHGString:
  480.     /* 
  481.      * PHGString is an IA5String (with case-insensitive comparisons).
  482.      * IA5 is ~almost~ ascii; ascii has dollar-sign where IA5 has
  483.      * currency symbol.
  484.      */
  485.     nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
  486.     break;
  487.   case nssStringType_GeneralString:
  488.     nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
  489.     break;
  490.   default:
  491.     nss_SetError(NSS_ERROR_UNSUPPORTED_TYPE);
  492.     break;
  493.   }
  494.   return rv;
  495. }
  496. NSS_IMPLEMENT NSSItem *
  497. nssUTF8_GetEncoding
  498. (
  499.   NSSArena *arenaOpt,
  500.   NSSItem *rvOpt,
  501.   nssStringType type,
  502.   NSSUTF8 *string
  503. )
  504. {
  505.   NSSItem *rv = (NSSItem *)NULL;
  506.   PRStatus status = PR_SUCCESS;
  507. #ifdef NSSDEBUG
  508.   if( (NSSArena *)NULL != arenaOpt ) {
  509.     if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
  510.       return (NSSItem *)NULL;
  511.     }
  512.   }
  513.   if( (NSSUTF8 *)NULL == string ) {
  514.     nss_SetError(NSS_ERROR_INVALID_POINTER);
  515.     return (NSSItem *)NULL;
  516.   }
  517. #endif /* NSSDEBUG */
  518.   switch( type ) {
  519.   case nssStringType_DirectoryString:
  520.     nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
  521.     break;
  522.   case nssStringType_TeletexString:
  523.     nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
  524.     break;
  525.   case nssStringType_PrintableString:
  526.     nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
  527.     break;
  528.   case nssStringType_UniversalString:
  529.     nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
  530.     break;
  531.   case nssStringType_BMPString:
  532.     nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
  533.     break;
  534.   case nssStringType_UTF8String:
  535.     {
  536.       NSSUTF8 *dup = nssUTF8_Duplicate(string, arenaOpt);
  537.       if( (NSSUTF8 *)NULL == dup ) {
  538.         return (NSSItem *)NULL;
  539.       }
  540.       if( (NSSItem *)NULL == rvOpt ) {
  541.         rv = nss_ZNEW(arenaOpt, NSSItem);
  542.         if( (NSSItem *)NULL == rv ) {
  543.           (void)nss_ZFreeIf(dup);
  544.           return (NSSItem *)NULL;
  545.         }
  546.       } else {
  547.         rv = rvOpt;
  548.       }
  549.       rv->data = dup;
  550.       dup = (NSSUTF8 *)NULL;
  551.       rv->size = nssUTF8_Size(rv->data, &status);
  552.       if( (0 == rv->size) && (PR_SUCCESS != status) ) {
  553.         if( (NSSItem *)NULL == rvOpt ) {
  554.           (void)nss_ZFreeIf(rv);
  555.         }
  556.         return (NSSItem *)NULL;
  557.       }
  558.     }
  559.     break;
  560.   case nssStringType_PHGString:
  561.     nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
  562.     break;
  563.   default:
  564.     nss_SetError(NSS_ERROR_UNSUPPORTED_TYPE);
  565.     break;
  566.   }
  567.   return rv;
  568. }
  569. /*
  570.  * nssUTF8_CopyIntoFixedBuffer
  571.  *
  572.  * This will copy a UTF8 string into a fixed-length buffer, making 
  573.  * sure that the all characters are valid.  Any remaining space will
  574.  * be padded with the specified ASCII character, typically either 
  575.  * null or space.
  576.  *
  577.  * Blah, blah, blah.
  578.  */
  579. NSS_IMPLEMENT PRStatus
  580. nssUTF8_CopyIntoFixedBuffer
  581. (
  582.   NSSUTF8 *string,
  583.   char *buffer,
  584.   PRUint32 bufferSize,
  585.   char pad
  586. )
  587. {
  588.   PRUint32 stringSize = 0;
  589. #ifdef NSSDEBUG
  590.   if( (char *)NULL == buffer ) {
  591.     nss_SetError(NSS_ERROR_INVALID_POINTER);
  592.     return PR_FALSE;
  593.   }
  594.   if( 0 == bufferSize ) {
  595.     nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
  596.     return PR_FALSE;
  597.   }
  598.   if( (pad & 0x80) != 0x00 ) {
  599.     nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
  600.     return PR_FALSE;
  601.   }
  602. #endif /* NSSDEBUG */
  603.   if( (NSSUTF8 *)NULL == string ) {
  604.     string = (unsigned char*) "";
  605.   }
  606.   stringSize = nssUTF8_Size(string, (PRStatus *)NULL);
  607.   stringSize--; /* don't count the trailing null */
  608.   if( stringSize > bufferSize ) {
  609.     PRUint32 bs = bufferSize;
  610.     (void)nsslibc_memcpy(buffer, string, bufferSize);
  611.     
  612.     if( (            ((buffer[ bs-1 ] & 0x80) == 0x00)) ||
  613.         ((bs > 1) && ((buffer[ bs-2 ] & 0xE0) == 0xC0)) ||
  614.         ((bs > 2) && ((buffer[ bs-3 ] & 0xF0) == 0xE0)) ||
  615.         ((bs > 3) && ((buffer[ bs-4 ] & 0xF8) == 0xF0)) ||
  616.         ((bs > 4) && ((buffer[ bs-5 ] & 0xFC) == 0xF8)) ||
  617.         ((bs > 5) && ((buffer[ bs-6 ] & 0xFE) == 0xFC)) ) {
  618.       /* It fit exactly */
  619.       return PR_SUCCESS;
  620.     }
  621.     /* Too long.  We have to trim the last character */
  622.     for( bs; bs > 0; bs-- ) {
  623.       if( (buffer[bs-1] & 0xC0) != 0x80 ) {
  624.         buffer[bs-1] = pad;
  625.         break;
  626.       } else {
  627.         buffer[bs-1] = pad;
  628.       }
  629.     }      
  630.   } else {
  631.     (void)nsslibc_memset(buffer, pad, bufferSize);
  632.     (void)nsslibc_memcpy(buffer, string, stringSize);
  633.   }
  634.   return PR_SUCCESS;
  635. }
  636. /*
  637.  * nssUTF8_Equal
  638.  *
  639.  */
  640. NSS_IMPLEMENT PRBool
  641. nssUTF8_Equal
  642. (
  643.   const NSSUTF8 *a,
  644.   const NSSUTF8 *b,
  645.   PRStatus *statusOpt
  646. )
  647. {
  648.   PRUint32 la, lb;
  649. #ifdef NSSDEBUG
  650.   if( ((const NSSUTF8 *)NULL == a) ||
  651.       ((const NSSUTF8 *)NULL == b) ) {
  652.     nss_SetError(NSS_ERROR_INVALID_POINTER);
  653.     if( (PRStatus *)NULL != statusOpt ) {
  654.       *statusOpt = PR_FAILURE;
  655.     }
  656.     return PR_FALSE;
  657.   }
  658. #endif /* NSSDEBUG */
  659.   la = nssUTF8_Size(a, statusOpt);
  660.   if( 0 == la ) {
  661.     return PR_FALSE;
  662.   }
  663.   lb = nssUTF8_Size(b, statusOpt);
  664.   if( 0 == lb ) {
  665.     return PR_FALSE;
  666.   }
  667.   if( la != lb ) {
  668.     return PR_FALSE;
  669.   }
  670.   return nsslibc_memequal(a, b, la, statusOpt);
  671. }