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