PostgreSQL Source Code git master
Loading...
Searching...
No Matches
unicode_norm.h File Reference
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Enumerations

enum  UnicodeNormalizationForm { UNICODE_NFC = 0 , UNICODE_NFD = 1 , UNICODE_NFKC = 2 , UNICODE_NFKD = 3 }
 
enum  UnicodeNormalizationQC { UNICODE_NORM_QC_NO = 0 , UNICODE_NORM_QC_YES = 1 , UNICODE_NORM_QC_MAYBE = -1 }
 

Functions

char32_tunicode_normalize (UnicodeNormalizationForm form, const char32_t *input)
 
UnicodeNormalizationQC unicode_is_normalized_quickcheck (UnicodeNormalizationForm form, const char32_t *input)
 

Enumeration Type Documentation

◆ UnicodeNormalizationForm

Enumerator
UNICODE_NFC 
UNICODE_NFD 
UNICODE_NFKC 
UNICODE_NFKD 

Definition at line 17 of file unicode_norm.h.

18{
19 UNICODE_NFC = 0,
20 UNICODE_NFD = 1,
21 UNICODE_NFKC = 2,
22 UNICODE_NFKD = 3,
UnicodeNormalizationForm
@ UNICODE_NFKD
@ UNICODE_NFD
@ UNICODE_NFC
@ UNICODE_NFKC

◆ UnicodeNormalizationQC

Enumerator
UNICODE_NORM_QC_NO 
UNICODE_NORM_QC_YES 
UNICODE_NORM_QC_MAYBE 

Definition at line 26 of file unicode_norm.h.

27{
UnicodeNormalizationQC
@ UNICODE_NORM_QC_YES
@ UNICODE_NORM_QC_NO
@ UNICODE_NORM_QC_MAYBE

Function Documentation

◆ unicode_is_normalized_quickcheck()

UnicodeNormalizationQC unicode_is_normalized_quickcheck ( UnicodeNormalizationForm  form,
const char32_t input 
)
extern

Definition at line 615 of file unicode_norm.c.

616{
619
620 /*
621 * For the "D" forms, we don't run the quickcheck. We don't include the
622 * lookup tables for those because they are huge, checking for these
623 * particular forms is less common, and running the slow path is faster
624 * for the "D" forms than the "C" forms because you don't need to
625 * recompose, which is slow.
626 */
627 if (form == UNICODE_NFD || form == UNICODE_NFKD)
629
630 for (const char32_t *p = input; *p; p++)
631 {
632 char32_t ch = *p;
635
638 return UNICODE_NORM_QC_NO;
639
640 check = qc_is_allowed(form, ch);
641 if (check == UNICODE_NORM_QC_NO)
642 return UNICODE_NORM_QC_NO;
643 else if (check == UNICODE_NORM_QC_MAYBE)
645
647 }
648 return result;
649}
uint8_t uint8
Definition c.h:681
uint32 result
FILE * input
static int fb(int x)
static uint8 get_canonical_class(char32_t code)
static UnicodeNormalizationQC qc_is_allowed(UnicodeNormalizationForm form, char32_t ch)

References fb(), get_canonical_class(), input, qc_is_allowed(), result, UNICODE_NFD, UNICODE_NFKD, UNICODE_NORM_QC_MAYBE, UNICODE_NORM_QC_NO, and UNICODE_NORM_QC_YES.

Referenced by unicode_is_normalized().

◆ unicode_normalize()

char32_t * unicode_normalize ( UnicodeNormalizationForm  form,
const char32_t input 
)
extern

Definition at line 401 of file unicode_norm.c.

402{
403 bool compat = (form == UNICODE_NFKC || form == UNICODE_NFKD);
404 bool recompose = (form == UNICODE_NFC || form == UNICODE_NFKC);
405 char32_t *decomp_chars;
406 char32_t *recomp_chars;
407 int decomp_size,
409 int count;
410 const char32_t *p;
411
412 /* variables for recomposition */
413 int last_class;
414 int starter_pos;
415 int target_pos;
417
418 /* First, do character decomposition */
419
420 /*
421 * Calculate how many characters long the decomposed version will be.
422 *
423 * Some characters decompose to quite a few code points, so that the
424 * decomposed version's size could overrun MaxAllocSize, and even 32-bit
425 * size_t, even though the input string presumably fits in that. In
426 * frontend we want to just return NULL in that case, so monitor the sum
427 * and exit early once we'd need more than MaxAllocSize bytes.
428 */
429 decomp_size = 0;
430 for (p = input; *p; p++)
431 {
433 if (unlikely(decomp_size > MaxAllocSize / sizeof(char32_t)))
434 {
435#ifndef FRONTEND
436 /* Exit loop and let palloc() throw error below */
437 break;
438#else
439 /* Just return NULL with no explicit error */
440 return NULL;
441#endif
442 }
443 }
444
445 decomp_chars = (char32_t *) ALLOC((decomp_size + 1) * sizeof(char32_t));
446 if (decomp_chars == NULL)
447 return NULL;
448
449 /*
450 * Now fill in each entry recursively. This needs a second pass on the
451 * decomposition table.
452 */
453 current_size = 0;
454 for (p = input; *p; p++)
458
459 /* Leave if there is nothing to decompose */
460 if (decomp_size == 0)
461 return decomp_chars;
462
463 /*
464 * Now apply canonical ordering.
465 */
466 for (count = 1; count < decomp_size; count++)
467 {
468 char32_t prev = decomp_chars[count - 1];
469 char32_t next = decomp_chars[count];
470 char32_t tmp;
471 const uint8 prevClass = get_canonical_class(prev);
473
474 /*
475 * Per Unicode (https://www.unicode.org/reports/tr15/tr15-18.html)
476 * annex 4, a sequence of two adjacent characters in a string is an
477 * exchangeable pair if the combining class (from the Unicode
478 * Character Database) for the first character is greater than the
479 * combining class for the second, and the second is not a starter. A
480 * character is a starter if its combining class is 0.
481 */
482 if (prevClass == 0 || nextClass == 0)
483 continue;
484
485 if (prevClass <= nextClass)
486 continue;
487
488 /* exchange can happen */
489 tmp = decomp_chars[count - 1];
490 decomp_chars[count - 1] = decomp_chars[count];
491 decomp_chars[count] = tmp;
492
493 /* backtrack to check again */
494 if (count > 1)
495 count -= 2;
496 }
497
498 if (!recompose)
499 return decomp_chars;
500
501 /*
502 * The last phase of NFC and NFKC is the recomposition of the reordered
503 * Unicode string using combining classes. The recomposed string cannot be
504 * longer than the decomposed one, so make the allocation of the output
505 * string based on that assumption.
506 */
507 recomp_chars = (char32_t *) ALLOC((decomp_size + 1) * sizeof(char32_t));
508 if (!recomp_chars)
509 {
511 return NULL;
512 }
513
514 last_class = -1; /* this eliminates a special check */
515 starter_pos = 0;
516 target_pos = 1;
518
519 for (count = 1; count < decomp_size; count++)
520 {
521 char32_t ch = decomp_chars[count];
523 char32_t composite;
524
525 if (last_class < ch_class &&
526 recompose_code(starter_ch, ch, &composite))
527 {
528 recomp_chars[starter_pos] = composite;
529 starter_ch = composite;
530 }
531 else if (ch_class == 0)
532 {
534 starter_ch = ch;
535 last_class = -1;
537 }
538 else
539 {
542 }
543 }
545
547
548 return recomp_chars;
549}
static int32 next
Definition blutils.c:225
#define Assert(condition)
Definition c.h:1002
#define unlikely(x)
Definition c.h:497
uint32_t uint32
Definition c.h:683
uint32_t char32_t
Definition c.h:1561
enum COMPAT_MODE compat
Definition ecpg.c:26
#define MaxAllocSize
Definition fe_memutils.h:22
static int64 current_size
static void decompose_code(char32_t code, bool compat, char32_t **result, int *current)
#define ALLOC(size)
#define FREE(size)
static int get_decomposed_size(char32_t code, bool compat)
static bool recompose_code(uint32 start, uint32 code, uint32 *result)

References ALLOC, Assert, compat, current_size, decompose_code(), fb(), FREE, get_canonical_class(), get_decomposed_size(), input, MaxAllocSize, next, recompose_code(), UNICODE_NFC, UNICODE_NFKC, UNICODE_NFKD, and unlikely.

Referenced by main(), pg_saslprep(), unicode_is_normalized(), and unicode_normalize_func().