Back to index

lightning-sunbird  0.9+nobinonly
utf8.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 
00037 #ifdef DEBUG
00038 static const char CVS_ID[] = "@(#) $RCSfile: utf8.c,v $ $Revision: 1.7 $ $Date: 2005/01/20 02:25:45 $";
00039 #endif /* DEBUG */
00040 
00041 /*
00042  * utf8.c
00043  *
00044  * This file contains some additional utility routines required for
00045  * handling UTF8 strings.
00046  */
00047 
00048 #ifndef BASE_H
00049 #include "base.h"
00050 #endif /* BASE_H */
00051 
00052 #include "plstr.h"
00053 
00054 /*
00055  * NOTES:
00056  *
00057  * There's an "is hex string" function in pki1/atav.c.  If we need
00058  * it in more places, pull that one out.
00059  */
00060 
00061 /*
00062  * nssUTF8_CaseIgnoreMatch
00063  * 
00064  * Returns true if the two UTF8-encoded strings pointed to by the 
00065  * two specified NSSUTF8 pointers differ only in typcase.
00066  *
00067  * The error may be one of the following values:
00068  *  NSS_ERROR_INVALID_POINTER
00069  *
00070  * Return value:
00071  *  PR_TRUE if the strings match, ignoring case
00072  *  PR_FALSE if they don't
00073  *  PR_FALSE upon error
00074  */
00075 
00076 NSS_IMPLEMENT PRBool
00077 nssUTF8_CaseIgnoreMatch
00078 (
00079   const NSSUTF8 *a,
00080   const NSSUTF8 *b,
00081   PRStatus *statusOpt
00082 )
00083 {
00084 #ifdef NSSDEBUG
00085   if( ((const NSSUTF8 *)NULL == a) ||
00086       ((const NSSUTF8 *)NULL == b) ) {
00087     nss_SetError(NSS_ERROR_INVALID_POINTER);
00088     if( (PRStatus *)NULL != statusOpt ) {
00089       *statusOpt = PR_FAILURE;
00090     }
00091     return PR_FALSE;
00092   }
00093 #endif /* NSSDEBUG */
00094 
00095   if( (PRStatus *)NULL != statusOpt ) {
00096     *statusOpt = PR_SUCCESS;
00097   }
00098 
00099   /*
00100    * XXX fgmr
00101    *
00102    * This is, like, so wrong!
00103    */
00104   if( 0 == PL_strcasecmp((const char *)a, (const char *)b) ) {
00105     return PR_TRUE;
00106   } else {
00107     return PR_FALSE;
00108   }
00109 }
00110 
00111 /*
00112  * nssUTF8_PrintableMatch
00113  *
00114  * Returns true if the two Printable strings pointed to by the 
00115  * two specified NSSUTF8 pointers match when compared with the 
00116  * rules for Printable String (leading and trailing spaces are 
00117  * disregarded, extents of whitespace match irregardless of length, 
00118  * and case is not significant), then PR_TRUE will be returned.
00119  * Otherwise, PR_FALSE will be returned.  Upon failure, PR_FALSE
00120  * will be returned.  If the optional statusOpt argument is not
00121  * NULL, then PR_SUCCESS or PR_FAILURE will be stored in that
00122  * location.
00123  *
00124  * The error may be one of the following values:
00125  *  NSS_ERROR_INVALID_POINTER
00126  *
00127  * Return value:
00128  *  PR_TRUE if the strings match, ignoring case
00129  *  PR_FALSE if they don't
00130  *  PR_FALSE upon error
00131  */
00132 
00133 NSS_IMPLEMENT PRBool
00134 nssUTF8_PrintableMatch
00135 (
00136   const NSSUTF8 *a,
00137   const NSSUTF8 *b,
00138   PRStatus *statusOpt
00139 )
00140 {
00141   PRUint8 *c;
00142   PRUint8 *d;
00143 
00144 #ifdef NSSDEBUG
00145   if( ((const NSSUTF8 *)NULL == a) ||
00146       ((const NSSUTF8 *)NULL == b) ) {
00147     nss_SetError(NSS_ERROR_INVALID_POINTER);
00148     if( (PRStatus *)NULL != statusOpt ) {
00149       *statusOpt = PR_FAILURE;
00150     }
00151     return PR_FALSE;
00152   }
00153 #endif /* NSSDEBUG */
00154 
00155   if( (PRStatus *)NULL != statusOpt ) {
00156     *statusOpt = PR_SUCCESS;
00157   }
00158 
00159   c = (PRUint8 *)a;
00160   d = (PRUint8 *)b;
00161 
00162   while( ' ' == *c ) {
00163     c++;
00164   }
00165 
00166   while( ' ' == *d ) {
00167     d++;
00168   }
00169 
00170   while( ('\0' != *c) && ('\0' != *d) ) {
00171     PRUint8 e, f;
00172 
00173     e = *c;
00174     f = *d;
00175     
00176     if( ('a' <= e) && (e <= 'z') ) {
00177       e -= ('a' - 'A');
00178     }
00179 
00180     if( ('a' <= f) && (f <= 'z') ) {
00181       f -= ('a' - 'A');
00182     }
00183 
00184     if( e != f ) {
00185       return PR_FALSE;
00186     }
00187 
00188     c++;
00189     d++;
00190 
00191     if( ' ' == *c ) {
00192       while( ' ' == *c ) {
00193         c++;
00194       }
00195       c--;
00196     }
00197 
00198     if( ' ' == *d ) {
00199       while( ' ' == *d ) {
00200         d++;
00201       }
00202       d--;
00203     }
00204   }
00205 
00206   while( ' ' == *c ) {
00207     c++;
00208   }
00209 
00210   while( ' ' == *d ) {
00211     d++;
00212   }
00213 
00214   if( *c == *d ) {
00215     /* And both '\0', btw */
00216     return PR_TRUE;
00217   } else {
00218     return PR_FALSE;
00219   }
00220 }
00221 
00222 /*
00223  * nssUTF8_Duplicate
00224  *
00225  * This routine duplicates the UTF8-encoded string pointed to by the
00226  * specified NSSUTF8 pointer.  If the optional arenaOpt argument is
00227  * not null, the memory required will be obtained from that arena;
00228  * otherwise, the memory required will be obtained from the heap.
00229  * A pointer to the new string will be returned.  In case of error,
00230  * an error will be placed on the error stack and NULL will be 
00231  * returned.
00232  *
00233  * The error may be one of the following values:
00234  *  NSS_ERROR_INVALID_POINTER
00235  *  NSS_ERROR_INVALID_ARENA
00236  *  NSS_ERROR_NO_MEMORY
00237  */
00238 
00239 NSS_IMPLEMENT NSSUTF8 *
00240 nssUTF8_Duplicate
00241 (
00242   const NSSUTF8 *s,
00243   NSSArena *arenaOpt
00244 )
00245 {
00246   NSSUTF8 *rv;
00247   PRUint32 len;
00248 
00249 #ifdef NSSDEBUG
00250   if( (const NSSUTF8 *)NULL == s ) {
00251     nss_SetError(NSS_ERROR_INVALID_POINTER);
00252     return (NSSUTF8 *)NULL;
00253   }
00254 
00255   if( (NSSArena *)NULL != arenaOpt ) {
00256     if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
00257       return (NSSUTF8 *)NULL;
00258     }
00259   }
00260 #endif /* NSSDEBUG */
00261 
00262   len = PL_strlen((const char *)s);
00263 #ifdef PEDANTIC
00264   if( '\0' != ((const char *)s)[ len ] ) {
00265     /* must have wrapped, e.g., too big for PRUint32 */
00266     nss_SetError(NSS_ERROR_NO_MEMORY);
00267     return (NSSUTF8 *)NULL;
00268   }
00269 #endif /* PEDANTIC */
00270   len++; /* zero termination */
00271 
00272   rv = nss_ZAlloc(arenaOpt, len);
00273   if( (void *)NULL == rv ) {
00274     return (NSSUTF8 *)NULL;
00275   }
00276 
00277   (void)nsslibc_memcpy(rv, s, len);
00278   return rv;
00279 }
00280 
00281 /*
00282  * nssUTF8_Size
00283  *
00284  * This routine returns the length in bytes (including the terminating
00285  * null) of the UTF8-encoded string pointed to by the specified
00286  * NSSUTF8 pointer.  Zero is returned on error.
00287  *
00288  * The error may be one of the following values:
00289  *  NSS_ERROR_INVALID_POINTER
00290  *  NSS_ERROR_VALUE_TOO_LARGE
00291  *
00292  * Return value:
00293  *  0 on error
00294  *  nonzero length of the string.
00295  */
00296 
00297 NSS_IMPLEMENT PRUint32
00298 nssUTF8_Size
00299 (
00300   const NSSUTF8 *s,
00301   PRStatus *statusOpt
00302 )
00303 {
00304   PRUint32 sv;
00305 
00306 #ifdef NSSDEBUG
00307   if( (const NSSUTF8 *)NULL == s ) {
00308     nss_SetError(NSS_ERROR_INVALID_POINTER);
00309     if( (PRStatus *)NULL != statusOpt ) {
00310       *statusOpt = PR_FAILURE;
00311     }
00312     return 0;
00313   }
00314 #endif /* NSSDEBUG */
00315 
00316   sv = PL_strlen((const char *)s) + 1;
00317 #ifdef PEDANTIC
00318   if( '\0' != ((const char *)s)[ sv-1 ] ) {
00319     /* wrapped */
00320     nss_SetError(NSS_ERROR_VALUE_TOO_LARGE);
00321     if( (PRStatus *)NULL != statusOpt ) {
00322       *statusOpt = PR_FAILURE;
00323     }
00324     return 0;
00325   }
00326 #endif /* PEDANTIC */
00327 
00328   if( (PRStatus *)NULL != statusOpt ) {
00329     *statusOpt = PR_SUCCESS;
00330   }
00331 
00332   return sv;
00333 }
00334 
00335 /*
00336  * nssUTF8_Length
00337  *
00338  * This routine returns the length in characters (not including the
00339  * terminating null) of the UTF8-encoded string pointed to by the
00340  * specified NSSUTF8 pointer.
00341  *
00342  * The error may be one of the following values:
00343  *  NSS_ERROR_INVALID_POINTER
00344  *  NSS_ERROR_VALUE_TOO_LARGE
00345  *  NSS_ERROR_INVALID_STRING
00346  *
00347  * Return value:
00348  *  length of the string (which may be zero)
00349  *  0 on error
00350  */
00351 
00352 NSS_IMPLEMENT PRUint32
00353 nssUTF8_Length
00354 (
00355   const NSSUTF8 *s,
00356   PRStatus *statusOpt
00357 )
00358 {
00359   PRUint32 l = 0;
00360   const PRUint8 *c = (const PRUint8 *)s;
00361 
00362 #ifdef NSSDEBUG
00363   if( (const NSSUTF8 *)NULL == s ) {
00364     nss_SetError(NSS_ERROR_INVALID_POINTER);
00365     goto loser;
00366   }
00367 #endif /* NSSDEBUG */
00368 
00369   /*
00370    * From RFC 2044:
00371    *
00372    * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
00373    * 0000 0000-0000 007F   0xxxxxxx
00374    * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
00375    * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
00376    * 0001 0000-001F FFFF   11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
00377    * 0020 0000-03FF FFFF   111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
00378    * 0400 0000-7FFF FFFF   1111110x 10xxxxxx ... 10xxxxxx
00379    */  
00380 
00381   while( 0 != *c ) {
00382     PRUint32 incr;
00383     if( (*c & 0x80) == 0 ) {
00384       incr = 1;
00385     } else if( (*c & 0xE0) == 0xC0 ) {
00386       incr = 2;
00387     } else if( (*c & 0xF0) == 0xE0 ) {
00388       incr = 3;
00389     } else if( (*c & 0xF8) == 0xF0 ) {
00390       incr = 4;
00391     } else if( (*c & 0xFC) == 0xF8 ) {
00392       incr = 5;
00393     } else if( (*c & 0xFE) == 0xFC ) {
00394       incr = 6;
00395     } else {
00396       nss_SetError(NSS_ERROR_INVALID_STRING);
00397       goto loser;
00398     }
00399 
00400     l += incr;
00401 
00402 #ifdef PEDANTIC
00403     if( l < incr ) {
00404       /* Wrapped-- too big */
00405       nss_SetError(NSS_ERROR_VALUE_TOO_LARGE);
00406       goto loser;
00407     }
00408 
00409     {
00410       PRUint8 *d;
00411       for( d = &c[1]; d < &c[incr]; d++ ) {
00412         if( (*d & 0xC0) != 0xF0 ) {
00413           nss_SetError(NSS_ERROR_INVALID_STRING);
00414           goto loser;
00415         }
00416       }
00417     }
00418 #endif /* PEDANTIC */
00419 
00420     c += incr;
00421   }
00422 
00423   if( (PRStatus *)NULL != statusOpt ) {
00424     *statusOpt = PR_SUCCESS;
00425   }
00426 
00427   return l;
00428 
00429  loser:
00430   if( (PRStatus *)NULL != statusOpt ) {
00431     *statusOpt = PR_FAILURE;
00432   }
00433 
00434   return 0;
00435 }
00436 
00437 
00438 /*
00439  * nssUTF8_Create
00440  *
00441  * This routine creates a UTF8 string from a string in some other
00442  * format.  Some types of string may include embedded null characters,
00443  * so for them the length parameter must be used.  For string types
00444  * that are null-terminated, the length parameter is optional; if it
00445  * is zero, it will be ignored.  If the optional arena argument is
00446  * non-null, the memory used for the new string will be obtained from
00447  * that arena, otherwise it will be obtained from the heap.  This
00448  * routine may return NULL upon error, in which case it will have
00449  * placed an error on the error stack.
00450  *
00451  * The error may be one of the following:
00452  *  NSS_ERROR_INVALID_POINTER
00453  *  NSS_ERROR_NO_MEMORY
00454  *  NSS_ERROR_UNSUPPORTED_TYPE
00455  *
00456  * Return value:
00457  *  NULL upon error
00458  *  A non-null pointer to a new UTF8 string otherwise
00459  */
00460 
00461 extern const NSSError NSS_ERROR_INTERNAL_ERROR; /* XXX fgmr */
00462 
00463 NSS_IMPLEMENT NSSUTF8 *
00464 nssUTF8_Create
00465 (
00466   NSSArena *arenaOpt,
00467   nssStringType type,
00468   const void *inputString,
00469   PRUint32 size /* in bytes, not characters */
00470 )
00471 {
00472   NSSUTF8 *rv = NULL;
00473 
00474 #ifdef NSSDEBUG
00475   if( (NSSArena *)NULL != arenaOpt ) {
00476     if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
00477       return (NSSUTF8 *)NULL;
00478     }
00479   }
00480 
00481   if( (const void *)NULL == inputString ) {
00482     nss_SetError(NSS_ERROR_INVALID_POINTER);
00483     return (NSSUTF8 *)NULL;
00484   }
00485 #endif /* NSSDEBUG */
00486 
00487   switch( type ) {
00488   case nssStringType_DirectoryString:
00489     /* This is a composite type requiring BER */
00490     nss_SetError(NSS_ERROR_UNSUPPORTED_TYPE);
00491     break;
00492   case nssStringType_TeletexString:
00493     /*
00494      * draft-ietf-pkix-ipki-part1-11 says in part:
00495      *
00496      * In addition, many legacy implementations support names encoded 
00497      * in the ISO 8859-1 character set (Latin1String) but tag them as 
00498      * TeletexString.  The Latin1String includes characters used in 
00499      * Western European countries which are not part of the 
00500      * TeletexString charcter set.  Implementations that process 
00501      * TeletexString SHOULD be prepared to handle the entire ISO 
00502      * 8859-1 character set.[ISO 8859-1].
00503      */
00504     nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
00505     break;
00506   case nssStringType_PrintableString:
00507     /*
00508      * PrintableString consists of A-Za-z0-9 ,()+,-./:=?
00509      * This is a subset of ASCII, which is a subset of UTF8.
00510      * So we can just duplicate the string over.
00511      */
00512 
00513     if( 0 == size ) {
00514       rv = nssUTF8_Duplicate((const NSSUTF8 *)inputString, arenaOpt);
00515     } else {
00516       rv = nss_ZAlloc(arenaOpt, size+1);
00517       if( (NSSUTF8 *)NULL == rv ) {
00518         return (NSSUTF8 *)NULL;
00519       }
00520 
00521       (void)nsslibc_memcpy(rv, inputString, size);
00522     }
00523 
00524     break;
00525   case nssStringType_UniversalString:
00526     /* 4-byte unicode */
00527     nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
00528     break;
00529   case nssStringType_BMPString:
00530     /* Base Multilingual Plane of Unicode */
00531     nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
00532     break;
00533   case nssStringType_UTF8String:
00534     if( 0 == size ) {
00535       rv = nssUTF8_Duplicate((const NSSUTF8 *)inputString, arenaOpt);
00536     } else {
00537       rv = nss_ZAlloc(arenaOpt, size+1);
00538       if( (NSSUTF8 *)NULL == rv ) {
00539         return (NSSUTF8 *)NULL;
00540       }
00541 
00542       (void)nsslibc_memcpy(rv, inputString, size);
00543     }
00544 
00545     break;
00546   case nssStringType_PHGString:
00547     /* 
00548      * PHGString is an IA5String (with case-insensitive comparisons).
00549      * IA5 is ~almost~ ascii; ascii has dollar-sign where IA5 has
00550      * currency symbol.
00551      */
00552     nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
00553     break;
00554   case nssStringType_GeneralString:
00555     nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
00556     break;
00557   default:
00558     nss_SetError(NSS_ERROR_UNSUPPORTED_TYPE);
00559     break;
00560   }
00561 
00562   return rv;
00563 }
00564 
00565 NSS_IMPLEMENT NSSItem *
00566 nssUTF8_GetEncoding
00567 (
00568   NSSArena *arenaOpt,
00569   NSSItem *rvOpt,
00570   nssStringType type,
00571   NSSUTF8 *string
00572 )
00573 {
00574   NSSItem *rv = (NSSItem *)NULL;
00575   PRStatus status = PR_SUCCESS;
00576 
00577 #ifdef NSSDEBUG
00578   if( (NSSArena *)NULL != arenaOpt ) {
00579     if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
00580       return (NSSItem *)NULL;
00581     }
00582   }
00583 
00584   if( (NSSUTF8 *)NULL == string ) {
00585     nss_SetError(NSS_ERROR_INVALID_POINTER);
00586     return (NSSItem *)NULL;
00587   }
00588 #endif /* NSSDEBUG */
00589 
00590   switch( type ) {
00591   case nssStringType_DirectoryString:
00592     nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
00593     break;
00594   case nssStringType_TeletexString:
00595     nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
00596     break;
00597   case nssStringType_PrintableString:
00598     nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
00599     break;
00600   case nssStringType_UniversalString:
00601     nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
00602     break;
00603   case nssStringType_BMPString:
00604     nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
00605     break;
00606   case nssStringType_UTF8String:
00607     {
00608       NSSUTF8 *dup = nssUTF8_Duplicate(string, arenaOpt);
00609       if( (NSSUTF8 *)NULL == dup ) {
00610         return (NSSItem *)NULL;
00611       }
00612 
00613       if( (NSSItem *)NULL == rvOpt ) {
00614         rv = nss_ZNEW(arenaOpt, NSSItem);
00615         if( (NSSItem *)NULL == rv ) {
00616           (void)nss_ZFreeIf(dup);
00617           return (NSSItem *)NULL;
00618         }
00619       } else {
00620         rv = rvOpt;
00621       }
00622 
00623       rv->data = dup;
00624       dup = (NSSUTF8 *)NULL;
00625       rv->size = nssUTF8_Size(rv->data, &status);
00626       if( (0 == rv->size) && (PR_SUCCESS != status) ) {
00627         if( (NSSItem *)NULL == rvOpt ) {
00628           (void)nss_ZFreeIf(rv);
00629         }
00630         return (NSSItem *)NULL;
00631       }
00632     }
00633     break;
00634   case nssStringType_PHGString:
00635     nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
00636     break;
00637   default:
00638     nss_SetError(NSS_ERROR_UNSUPPORTED_TYPE);
00639     break;
00640   }
00641 
00642   return rv;
00643 }
00644 
00645 /*
00646  * nssUTF8_CopyIntoFixedBuffer
00647  *
00648  * This will copy a UTF8 string into a fixed-length buffer, making 
00649  * sure that the all characters are valid.  Any remaining space will
00650  * be padded with the specified ASCII character, typically either 
00651  * null or space.
00652  *
00653  * Blah, blah, blah.
00654  */
00655 
00656 NSS_IMPLEMENT PRStatus
00657 nssUTF8_CopyIntoFixedBuffer
00658 (
00659   NSSUTF8 *string,
00660   char *buffer,
00661   PRUint32 bufferSize,
00662   char pad
00663 )
00664 {
00665   PRUint32 stringSize = 0;
00666 
00667 #ifdef NSSDEBUG
00668   if( (char *)NULL == buffer ) {
00669     nss_SetError(NSS_ERROR_INVALID_POINTER);
00670     return PR_FALSE;
00671   }
00672 
00673   if( 0 == bufferSize ) {
00674     nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
00675     return PR_FALSE;
00676   }
00677 
00678   if( (pad & 0x80) != 0x00 ) {
00679     nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
00680     return PR_FALSE;
00681   }
00682 #endif /* NSSDEBUG */
00683 
00684   if( (NSSUTF8 *)NULL == string ) {
00685     string = (NSSUTF8 *) "";
00686   }
00687 
00688   stringSize = nssUTF8_Size(string, (PRStatus *)NULL);
00689   stringSize--; /* don't count the trailing null */
00690   if( stringSize > bufferSize ) {
00691     PRUint32 bs = bufferSize;
00692     (void)nsslibc_memcpy(buffer, string, bufferSize);
00693     
00694     if( (            ((buffer[ bs-1 ] & 0x80) == 0x00)) ||
00695         ((bs > 1) && ((buffer[ bs-2 ] & 0xE0) == 0xC0)) ||
00696         ((bs > 2) && ((buffer[ bs-3 ] & 0xF0) == 0xE0)) ||
00697         ((bs > 3) && ((buffer[ bs-4 ] & 0xF8) == 0xF0)) ||
00698         ((bs > 4) && ((buffer[ bs-5 ] & 0xFC) == 0xF8)) ||
00699         ((bs > 5) && ((buffer[ bs-6 ] & 0xFE) == 0xFC)) ) {
00700       /* It fit exactly */
00701       return PR_SUCCESS;
00702     }
00703 
00704     /* Too long.  We have to trim the last character */
00705     for( /*bs*/; bs != 0; bs-- ) {
00706       if( (buffer[bs-1] & 0xC0) != 0x80 ) {
00707         buffer[bs-1] = pad;
00708         break;
00709       } else {
00710         buffer[bs-1] = pad;
00711       }
00712     }      
00713   } else {
00714     (void)nsslibc_memset(buffer, pad, bufferSize);
00715     (void)nsslibc_memcpy(buffer, string, stringSize);
00716   }
00717 
00718   return PR_SUCCESS;
00719 }
00720 
00721 /*
00722  * nssUTF8_Equal
00723  *
00724  */
00725 
00726 NSS_IMPLEMENT PRBool
00727 nssUTF8_Equal
00728 (
00729   const NSSUTF8 *a,
00730   const NSSUTF8 *b,
00731   PRStatus *statusOpt
00732 )
00733 {
00734   PRUint32 la, lb;
00735 
00736 #ifdef NSSDEBUG
00737   if( ((const NSSUTF8 *)NULL == a) ||
00738       ((const NSSUTF8 *)NULL == b) ) {
00739     nss_SetError(NSS_ERROR_INVALID_POINTER);
00740     if( (PRStatus *)NULL != statusOpt ) {
00741       *statusOpt = PR_FAILURE;
00742     }
00743     return PR_FALSE;
00744   }
00745 #endif /* NSSDEBUG */
00746 
00747   la = nssUTF8_Size(a, statusOpt);
00748   if( 0 == la ) {
00749     return PR_FALSE;
00750   }
00751 
00752   lb = nssUTF8_Size(b, statusOpt);
00753   if( 0 == lb ) {
00754     return PR_FALSE;
00755   }
00756 
00757   if( la != lb ) {
00758     return PR_FALSE;
00759   }
00760 
00761   return nsslibc_memequal(a, b, la, statusOpt);
00762 }