comparison nss/lib/base/nssutf8.c @ 0:1e5118fa0cb1

This is NSS with a Cmake Buildsyste To compile a static NSS library for Windows we've used the Chromium-NSS fork and added a Cmake buildsystem to compile it statically for Windows. See README.chromium for chromium changes and README.trustbridge for our modifications.
author Andre Heinecke <andre.heinecke@intevation.de>
date Mon, 28 Jul 2014 10:47:06 +0200
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:1e5118fa0cb1
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 }
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)