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