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