libutf: utf32be_to_utf8

This commit is contained in:
dtb 2024-05-29 16:32:31 -06:00
parent 2479ab63d0
commit 7ed5c95e0f
Signed by: trinity
GPG Key ID: 6CDF230C17CC3349
2 changed files with 68 additions and 18 deletions

View File

@ -1,14 +1,37 @@
#include <stdlib.h> /* size_t */
#include "libutf.h"
/* UTF-32BE is the big-endian literal encoding of a Unicode codepoint,
* including 11 bits of padding. The following functions convert from and to
* UTF-32. */
/* This is functionally equivalent to the UTF-32-specific conversion functions
* but very slightly slower than each. */
/* This operation is symmetrical; swab32(swab32(c)) will always return c. */
/* big-endian | ZZZZ YYYY | XXXX WWWW | VVVV UUUU | TTTT SSSS */
/* little-endian | TTTT SSSS | VVVV UUUU | */
rune_t
swab32(rune_t c){ return
((c & 0xFF000000) >> 24)
| ((c & 0x00FF0000) >> 8)
| ((c & 0x0000FF00) << 8)
| ((c & 0x000000FF) << 24);
}
/* From <https://en.wikipedia.org/wiki/UTF-8>, UTF-8 is encoded as follows:
* The codepoint 0bZYYYY_XXXXWWWW_VVVVUUUU is nestled within the literal bits 0
* and 1; letters denote nybbles here, little-endian, and certain bits are
* labeled, also little-endian. */
/* utf-8 bits |32 |24 |16 |8
* U+001000 to U+10FFFF | 1111 0ZYY | 10YY XXXX | 10WW WWVV | 10VV UUUU *
* U+000800 to U+00FFFF | 0000 0000 | 1110 XXXX | 10WW WWVV | 10VV UUUU *
* U+000080 to U+0007FF | 0000 0000 | 0000 0000 | 110W WWVV | 10VV UUUU *
* U+000000 to U+00007F | 0000 0000 | 0000 0000 | 0000 0000 | 0VVV UUUU */
size_t
utf8_size(rune_t c){ return
1 + ((c & 0x80000000) >> 31) /* 4B? */
+ ((c & 0x00800000) >> 23) /* 3B? */
+ ((c & 0x00008000) >> 15) /* 2B? */
+ ((c & 0x00000080) >> 7); /* 1B? */
}
/* utf-8 bits |32 |27 |22 |14 |7
* U+001000 to U+10FFFF | 1111 0ZYY | 10YY XXXX | 10WW WWVV | 10VV UUUU *
* U+000800 to U+00FFFF | 0000 0000 | 1110 XXXX | 10WW WWVV | 10VV UUUU *
@ -16,7 +39,7 @@
* U+000000 to U+00007F | 0000 0000 | 0000 0000 | 0000 0000 | 0VVV UUUU */
/* utf-32be bits |32 |21 |18 |12 |6
* U+000000 to U+10FFFF | 0000 0000 | 000Z YYYY | XXXX WWWW | VVVV UUUU */
codepoint_t
rune_t
utf8_to_utf32be(rune_t c){ return
((c & 0x07000000) >> 6) /* UTF-8 b27-25 -> UTF-32 b21-19 */
| (((c & 0x003F0000) /* UTF-8 b22-17 -> UTF-32 b18-13 */
@ -24,6 +47,41 @@ utf8_to_utf32be(rune_t c){ return
| ((c & 0x00003F00) >> 2) /* UTF-8 b14- 9 -> UTF-32 b12- 7 */
| (c & 0x0000007F); /* UTF-32 b 7- 1 */
}
/* utf-32be bits |32 |21 |18 |12 |6
* U+000000 to U+10FFFF | 0000 0000 | 000Z YYYY | XXXX WWWW | VVVV UUUU */
/* utf-8 bits |32 |27 |22 |14 |7
* U+001000 to U+10FFFF | 1111 0ZYY | 10YY XXXX | 10WW WWVV | 10VV UUUU *
* U+000800 to U+00FFFF | 0000 0000 | 1110 XXXX | 10WW WWVV | 10VV UUUU *
* U+000080 to U+0007FF | 0000 0000 | 0000 0000 | 110W WWVV | 10VV UUUU *
* U+000000 to U+00007F | 0000 0000 | 0000 0000 | 0000 0000 | 0VVV UUUU */
/* m is the minimum amount of bytes into which to encode the codepoint c. If m
* is greater than 0, this function may return overlong-encoded UTF-8. */
rune_t
utf32be_to_utf8(rune_t c, size_t m){
rune_t r;
{ size_t n;
if((n = utf8_size(c)) > m)
m = n; } /* This avoids calculating the size twice. */
switch(m){ /* "Trin's device" if this is a novel use of a switch. */
case 4: r = 0xF0000000 /* UTF-8 b32-29 */
| ((c & 0x1C0000) << 6) /* UTF-32 b21-19 -> UTF-8 b27-25 */
| 0x00800000 /* UTF-8 b24-23 */
| ((c & 0x03F000) << 4); /* UTF-32 b18-13 -> UTF-8 b24-17 */
if(m == 3)
case 3: r = (0xE << 4) /* UTF-8 b24-21 */
| ((c & 0x00F000) << 4); /* UTF-32 b16-13 -> UTF-8 b20-17 */
r |= 0x00008000 /* UTF-8 b16-15 */
| ((c & 0x000FC0) << 2); /* UTF-32 b12- 7 -> UTF-8 b14- 9 */
if(m == 2)
case 2: r = (0xE << 3) /* UTF-8 b16-14 */
| ((c & 0x007C00) << 2); /* UTF-32 b11- 7 -> UTF-8 b13- 9 */
r |= 0x00000080 /* UTF-8 b 8- 7 */
| (c & 0x00003F); /* UTF-8 b 6- 1 */
if(m == 1)
case 1: r = c & 0x00007F; /* UTF-8 b 7- 1 */
}
return r;
}
/* <https://www.herongyang.com/Unicode/UTF-32-UTF-32-Encoding.html> is a good
* explanation of this. */
@ -31,25 +89,15 @@ utf8_to_utf32be(rune_t c){ return
* U+000000 to U+10FFFF | 0000 0000 | 000Z YYYY | XXXX WWWW | VVVV UUUU */
/* utf-32le bits
* U+000000 to U+10FFFF | VVVV UUUU | XXXX WWWW | 000Z YYYY | 0000 0000 */
codepoint_t
utf32be_to_utf32le(codepoint_t c){ return
rune_t
utf32be_to_utf32le(rune_t c){ return
((c & 0x000000FF) << 24)
| ((c & 0x0000FF00) << 8)
| ((c & 0x001F0000) >> 8);
}
codepoint_t
utf32le_to_utf32be(codepoint_t c){ return
rune_t
utf32le_to_utf32be(rune_t c){ return
((c & 0xFF000000) >> 24)
| ((c & 0x00FF0000) >> 8)
| ((c & 0x00001F00) << 8);
}
/* This operation is symmetrical; swab32(swab32(c)) will always return c. It's
* (very slightly) slower than the specific UTF-32 conversion functions but may
* be useful. */
codepoint_t
swab32(codepoint_t c){ return
((c & 0xFF000000) >> 24)
| ((c & 0x00FF0000) >> 8)
| ((c & 0x0000FF00) << 8)
| ((c & 0x000000FF) << 24);
}

View File

@ -7,8 +7,10 @@ typedef uint32_t rune_t;
* <http://jfxpt.com/library/c89-draft.html#2.2.4.2> */
typedef unsigned long int rune_t;
#endif
#include <stddef.h> /* size_t */
rune_t swab32(rune_t c);
rune_t utf8_to_utf32be(rune_t c);
rune_t utf32be_to_utf8(rune_t c, size_t m);
rune_t utf32be_to_utf32le(rune_t c);
rune_t utf32le_to_utf32be(rune_t c);