PostgreSQL Source Code git master
Loading...
Searching...
No Matches
unicode_norm.c File Reference
Include dependency graph for unicode_norm.c:

Go to the source code of this file.

Macros

#define ALLOC(size)   palloc(size)
 
#define FREE(size)   pfree(size)
 
#define SBASE   0xAC00 /* U+AC00 */
 
#define LBASE   0x1100 /* U+1100 */
 
#define VBASE   0x1161 /* U+1161 */
 
#define TBASE   0x11A7 /* U+11A7 */
 
#define LCOUNT   19
 
#define VCOUNT   21
 
#define TCOUNT   28
 
#define NCOUNT   VCOUNT * TCOUNT
 
#define SCOUNT   LCOUNT * NCOUNT
 

Functions

static const pg_unicode_decompositionget_code_entry (char32_t code)
 
static uint8 get_canonical_class (char32_t code)
 
static const char32_tget_code_decomposition (const pg_unicode_decomposition *entry, int *dec_size)
 
static int get_decomposed_size (char32_t code, bool compat)
 
static bool recompose_code (uint32 start, uint32 code, uint32 *result)
 
static void decompose_code (char32_t code, bool compat, char32_t **result, int *current)
 
char32_tunicode_normalize (UnicodeNormalizationForm form, const char32_t *input)
 
static const pg_unicode_normpropsqc_hash_lookup (char32_t ch, const pg_unicode_norminfo *norminfo)
 
static UnicodeNormalizationQC qc_is_allowed (UnicodeNormalizationForm form, char32_t ch)
 
UnicodeNormalizationQC unicode_is_normalized_quickcheck (UnicodeNormalizationForm form, const char32_t *input)
 

Macro Definition Documentation

◆ ALLOC

#define ALLOC (   size)    palloc(size)

Definition at line 32 of file unicode_norm.c.

◆ FREE

#define FREE (   size)    pfree(size)

Definition at line 33 of file unicode_norm.c.

◆ LBASE

#define LBASE   0x1100 /* U+1100 */

Definition at line 41 of file unicode_norm.c.

◆ LCOUNT

#define LCOUNT   19

Definition at line 44 of file unicode_norm.c.

◆ NCOUNT

#define NCOUNT   VCOUNT * TCOUNT

Definition at line 47 of file unicode_norm.c.

◆ SBASE

#define SBASE   0xAC00 /* U+AC00 */

Definition at line 40 of file unicode_norm.c.

◆ SCOUNT

#define SCOUNT   LCOUNT * NCOUNT

Definition at line 48 of file unicode_norm.c.

◆ TBASE

#define TBASE   0x11A7 /* U+11A7 */

Definition at line 43 of file unicode_norm.c.

◆ TCOUNT

#define TCOUNT   28

Definition at line 46 of file unicode_norm.c.

◆ VBASE

#define VBASE   0x1161 /* U+1161 */

Definition at line 42 of file unicode_norm.c.

◆ VCOUNT

#define VCOUNT   21

Definition at line 45 of file unicode_norm.c.

Function Documentation

◆ decompose_code()

static void decompose_code ( char32_t  code,
bool  compat,
char32_t **  result,
int current 
)
static

Definition at line 320 of file unicode_norm.c.

321{
322 const pg_unicode_decomposition *entry;
323 int i;
324 const uint32 *decomp;
325 int dec_size;
326
327 /*
328 * Fast path for Hangul characters not stored in tables to save memory as
329 * decomposition is algorithmic. See
330 * https://www.unicode.org/reports/tr15/tr15-18.html, annex 10 for details
331 * on the matter.
332 */
333 if (code >= SBASE && code < SBASE + SCOUNT)
334 {
335 uint32 l,
336 v,
337 tindex,
338 sindex;
339 char32_t *res = *result;
340
341 sindex = code - SBASE;
342 l = LBASE + sindex / (VCOUNT * TCOUNT);
343 v = VBASE + (sindex % (VCOUNT * TCOUNT)) / TCOUNT;
344 tindex = sindex % TCOUNT;
345
346 res[*current] = l;
347 (*current)++;
348 res[*current] = v;
349 (*current)++;
350
351 if (tindex != 0)
352 {
353 res[*current] = TBASE + tindex;
354 (*current)++;
355 }
356
357 return;
358 }
359
360 entry = get_code_entry(code);
361
362 /*
363 * Just fill in with the current decomposition if there are no
364 * decomposition codes to recurse to. A NULL entry is equivalent to a
365 * character with class 0 and no decompositions, so just leave also in
366 * this case.
367 */
368 if (entry == NULL || DECOMPOSITION_SIZE(entry) == 0 ||
369 (!compat && DECOMPOSITION_IS_COMPAT(entry)))
370 {
371 char32_t *res = *result;
372
373 res[*current] = code;
374 (*current)++;
375 return;
376 }
377
378 /*
379 * If this entry has other decomposition codes look at them as well.
380 */
382 for (i = 0; i < dec_size; i++)
383 {
384 char32_t lcode = (char32_t) decomp[i];
385
386 /* Leave if no more decompositions */
387 decompose_code(lcode, compat, result, current);
388 }
389}
uint32_t uint32
Definition c.h:683
uint32_t char32_t
Definition c.h:1561
uint32 result
enum COMPAT_MODE compat
Definition ecpg.c:26
int i
Definition isn.c:77
static int fb(int x)
static void decompose_code(char32_t code, bool compat, char32_t **result, int *current)
#define TCOUNT
#define TBASE
#define VBASE
#define VCOUNT
#define LBASE
static const char32_t * get_code_decomposition(const pg_unicode_decomposition *entry, int *dec_size)
static const pg_unicode_decomposition * get_code_entry(char32_t code)
#define SBASE
#define SCOUNT
#define DECOMPOSITION_IS_COMPAT(x)
#define DECOMPOSITION_SIZE(x)

References compat, decompose_code(), DECOMPOSITION_IS_COMPAT, DECOMPOSITION_SIZE, fb(), get_code_decomposition(), get_code_entry(), i, LBASE, result, SBASE, SCOUNT, TBASE, TCOUNT, VBASE, and VCOUNT.

Referenced by decompose_code(), and unicode_normalize().

◆ get_canonical_class()

static uint8 get_canonical_class ( char32_t  code)
static

Definition at line 113 of file unicode_norm.c.

114{
115 const pg_unicode_decomposition *entry = get_code_entry(code);
116
117 /*
118 * If no entries are found, the character used is either a Hangul
119 * character or a character with a class of 0 and no decompositions.
120 */
121 if (!entry)
122 return 0;
123 else
124 return entry->comb_class;
125}

References pg_unicode_decomposition::comb_class, and get_code_entry().

Referenced by unicode_is_normalized_quickcheck(), and unicode_normalize().

◆ get_code_decomposition()

static const char32_t * get_code_decomposition ( const pg_unicode_decomposition entry,
int dec_size 
)
static

Definition at line 135 of file unicode_norm.c.

136{
137 static char32_t x;
138
139 if (DECOMPOSITION_IS_INLINE(entry))
140 {
141 Assert(DECOMPOSITION_SIZE(entry) == 1);
142 x = (char32_t) entry->dec_index;
143 *dec_size = 1;
144 return &x;
145 }
146 else
147 {
149 return &UnicodeDecomp_codepoints[entry->dec_index];
150 }
151}
#define Assert(condition)
Definition c.h:1002
int x
Definition isn.c:75
static const uint32 UnicodeDecomp_codepoints[5138]
#define DECOMPOSITION_IS_INLINE(x)

References Assert, pg_unicode_decomposition::dec_index, DECOMPOSITION_IS_INLINE, DECOMPOSITION_SIZE, fb(), UnicodeDecomp_codepoints, and x.

Referenced by decompose_code(), and get_decomposed_size().

◆ get_code_entry()

static const pg_unicode_decomposition * get_code_entry ( char32_t  code)
static

Definition at line 73 of file unicode_norm.c.

74{
75#ifndef FRONTEND
76 int h;
79
80 /*
81 * Compute the hash function. The hash key is the codepoint with the bytes
82 * in network order.
83 */
84 hashkey = pg_hton32(code);
85 h = decompinfo.hash(&hashkey);
86
87 /* An out-of-range result implies no match */
88 if (h < 0 || h >= decompinfo.num_decomps)
89 return NULL;
90
91 /*
92 * Since it's a perfect hash, we need only match to the specific codepoint
93 * it identifies.
94 */
95 if (code != decompinfo.decomps[h].codepoint)
96 return NULL;
97
98 /* Success! */
99 return &decompinfo.decomps[h];
100#else
101 return bsearch(&(code),
106#endif
107}
#define lengthof(array)
Definition c.h:932
#define pg_hton32(x)
Definition pg_bswap.h:121
static const pg_unicode_decompinfo UnicodeDecompInfo
static const pg_unicode_decomposition UnicodeDecompMain[6878]

References fb(), lengthof, pg_hton32, UnicodeDecompInfo, and UnicodeDecompMain.

Referenced by decompose_code(), get_canonical_class(), and get_decomposed_size().

◆ get_decomposed_size()

static int get_decomposed_size ( char32_t  code,
bool  compat 
)
static

Definition at line 160 of file unicode_norm.c.

161{
162 const pg_unicode_decomposition *entry;
163 int size = 0;
164 int i;
165 const uint32 *decomp;
166 int dec_size;
167
168 /*
169 * Fast path for Hangul characters not stored in tables to save memory as
170 * decomposition is algorithmic. See
171 * https://www.unicode.org/reports/tr15/tr15-18.html, annex 10 for details
172 * on the matter.
173 */
174 if (code >= SBASE && code < SBASE + SCOUNT)
175 {
177 sindex;
178
179 sindex = code - SBASE;
180 tindex = sindex % TCOUNT;
181
182 if (tindex != 0)
183 return 3;
184 return 2;
185 }
186
187 entry = get_code_entry(code);
188
189 /*
190 * Just count current code if no other decompositions. A NULL entry is
191 * equivalent to a character with class 0 and no decompositions.
192 */
193 if (entry == NULL || DECOMPOSITION_SIZE(entry) == 0 ||
194 (!compat && DECOMPOSITION_IS_COMPAT(entry)))
195 return 1;
196
197 /*
198 * If this entry has other decomposition codes look at them as well. First
199 * get its decomposition in the list of tables available.
200 */
202 for (i = 0; i < dec_size; i++)
203 {
204 uint32 lcode = decomp[i];
205
207 }
208
209 return size;
210}
static int get_decomposed_size(char32_t code, bool compat)

References compat, DECOMPOSITION_IS_COMPAT, DECOMPOSITION_SIZE, fb(), get_code_decomposition(), get_code_entry(), get_decomposed_size(), i, SBASE, SCOUNT, and TCOUNT.

Referenced by get_decomposed_size(), and unicode_normalize().

◆ qc_hash_lookup()

static const pg_unicode_normprops * qc_hash_lookup ( char32_t  ch,
const pg_unicode_norminfo norminfo 
)
static

Definition at line 560 of file unicode_norm.c.

561{
562 int h;
564
565 /*
566 * Compute the hash function. The hash key is the codepoint with the bytes
567 * in network order.
568 */
570 h = norminfo->hash(&hashkey);
571
572 /* An out-of-range result implies no match */
573 if (h < 0 || h >= norminfo->num_normprops)
574 return NULL;
575
576 /*
577 * Since it's a perfect hash, we need only match to the specific codepoint
578 * it identifies.
579 */
580 if (ch != norminfo->normprops[h].codepoint)
581 return NULL;
582
583 /* Success! */
584 return &norminfo->normprops[h];
585}

References fb(), and pg_hton32.

Referenced by qc_is_allowed().

◆ qc_is_allowed()

static UnicodeNormalizationQC qc_is_allowed ( UnicodeNormalizationForm  form,
char32_t  ch 
)
static

Definition at line 591 of file unicode_norm.c.

592{
593 const pg_unicode_normprops *found = NULL;
594
595 switch (form)
596 {
597 case UNICODE_NFC:
599 break;
600 case UNICODE_NFKC:
602 break;
603 default:
604 Assert(false);
605 break;
606 }
607
608 if (found)
609 return found->quickcheck;
610 else
611 return UNICODE_NORM_QC_YES;
612}
static const pg_unicode_normprops * qc_hash_lookup(char32_t ch, const pg_unicode_norminfo *norminfo)
@ UNICODE_NFC
@ UNICODE_NFKC
@ UNICODE_NORM_QC_YES
static const pg_unicode_norminfo UnicodeNormInfo_NFKC_QC
static const pg_unicode_norminfo UnicodeNormInfo_NFC_QC

References Assert, fb(), qc_hash_lookup(), pg_unicode_normprops::quickcheck, UNICODE_NFC, UNICODE_NFKC, UNICODE_NORM_QC_YES, UnicodeNormInfo_NFC_QC, and UnicodeNormInfo_NFKC_QC.

Referenced by unicode_is_normalized_quickcheck().

◆ recompose_code()

static bool recompose_code ( uint32  start,
uint32  code,
uint32 result 
)
static

Definition at line 219 of file unicode_norm.c.

220{
221 /*
222 * Handle Hangul characters algorithmically, per the Unicode spec.
223 *
224 * Check if two current characters are L and V.
225 */
226 if (start >= LBASE && start < LBASE + LCOUNT &&
227 code >= VBASE && code < VBASE + VCOUNT)
228 {
229 /* make syllable of form LV */
231 uint32 vindex = code - VBASE;
232
233 *result = SBASE + (lindex * VCOUNT + vindex) * TCOUNT;
234 return true;
235 }
236 /* Check if two current characters are LV and T */
237 else if (start >= SBASE && start < (SBASE + SCOUNT) &&
238 ((start - SBASE) % TCOUNT) == 0 &&
239 code > TBASE && code < (TBASE + TCOUNT))
240 {
241 /* make syllable of form LVT */
242 uint32 tindex = code - TBASE;
243
244 *result = start + tindex;
245 return true;
246 }
247 else
248 {
249 const pg_unicode_decomposition *entry;
250
251 /*
252 * Do an inverse lookup of the decomposition tables to see if anything
253 * matches. The comparison just needs to be a perfect match on the
254 * sub-table of size two, because the start character has already been
255 * recomposed partially. This lookup uses a perfect hash function for
256 * the backend code.
257 */
258#ifndef FRONTEND
259
260 int h,
264
265 /*
266 * Compute the hash function. The hash key is formed by concatenating
267 * bytes of the two codepoints in network order. See also
268 * src/common/unicode/generate-unicode_norm_table.pl.
269 */
270 hashkey = pg_hton64(((uint64) start << 32) | (uint64) code);
271 h = recompinfo.hash(&hashkey);
272
273 /* An out-of-range result implies no match */
274 if (h < 0 || h >= recompinfo.num_recomps)
275 return false;
276
277 inv_lookup_index = recompinfo.inverse_lookup[h];
279
281 code == UnicodeDecomp_codepoints[entry->dec_index + 1])
282 {
283 *result = entry->codepoint;
284 return true;
285 }
286
287#else
288
289 for (size_t i = 0; i < lengthof(UnicodeDecompMain); i++)
290 {
291 entry = &UnicodeDecompMain[i];
292
293 if (DECOMPOSITION_SIZE(entry) != 2)
294 continue;
295
296 if (DECOMPOSITION_NO_COMPOSE(entry))
297 continue;
298
300 code == UnicodeDecomp_codepoints[entry->dec_index + 1])
301 {
302 *result = entry->codepoint;
303 return true;
304 }
305 }
306#endif /* !FRONTEND */
307 }
308
309 return false;
310}
uint64_t uint64
Definition c.h:684
return str start
#define pg_hton64(x)
Definition pg_bswap.h:122
#define LCOUNT
static const pg_unicode_recompinfo UnicodeRecompInfo
#define DECOMPOSITION_NO_COMPOSE(x)

References pg_unicode_decomposition::codepoint, pg_unicode_decomposition::dec_index, DECOMPOSITION_NO_COMPOSE, DECOMPOSITION_SIZE, fb(), i, LBASE, LCOUNT, lengthof, pg_hton64, result, SBASE, SCOUNT, start, TBASE, TCOUNT, UnicodeDecomp_codepoints, UnicodeDecompMain, UnicodeRecompInfo, VBASE, and VCOUNT.

Referenced by unicode_normalize().

◆ unicode_is_normalized_quickcheck()

UnicodeNormalizationQC unicode_is_normalized_quickcheck ( UnicodeNormalizationForm  form,
const char32_t input 
)

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
FILE * input
static uint8 get_canonical_class(char32_t code)
static UnicodeNormalizationQC qc_is_allowed(UnicodeNormalizationForm form, char32_t ch)
@ UNICODE_NFKD
@ UNICODE_NFD
UnicodeNormalizationQC
@ UNICODE_NORM_QC_NO
@ UNICODE_NORM_QC_MAYBE

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 
)

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 unlikely(x)
Definition c.h:497
#define MaxAllocSize
Definition fe_memutils.h:22
static int64 current_size
#define ALLOC(size)
#define FREE(size)
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().