Usermode - Moved UTF-8 handling into a library
[tpg/acess2.git] / Usermode / Libraries / libunicode.so_src / utf-8.c
1 /*
2  * Acess2 "libunicode" UTF Parser
3  * - By John Hodge (thePowersGang)
4  *
5  * utf-8.c
6  * - UTF-8 Parsing code
7  */
8 #include <stdint.h>
9 #include <unicode.h>
10
11 /**
12  * \brief Read a UTF-8 character from a string
13  * \param Input Source UTF-8 encoded string
14  * \param Val   Destination for read codepoint
15  * \return Number of bytes read/used
16  */
17 int ReadUTF8(const char *Input, uint32_t *Val)
18 {
19         const uint8_t   *str = (const uint8_t *)Input;
20         *Val = 0xFFFD;  // Assume invalid character
21         
22         // ASCII
23         if( !(*str & 0x80) ) {
24                 *Val = *str;
25                 return 1;
26         }
27         
28         // Middle of a sequence
29         if( (*str & 0xC0) == 0x80 ) {
30                 return 1;
31         }
32         
33         // Two Byte
34         if( (*str & 0xE0) == 0xC0 ) {
35                 *Val = (*str & 0x1F) << 6;      // Upper 6 Bits
36                 str ++;
37                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
38                 *Val |= (*str & 0x3F);  // Lower 6 Bits
39                 return 2;
40         }
41         
42         // Three Byte
43         if( (*str & 0xF0) == 0xE0 ) {
44                 *Val = (*str & 0x0F) << 12;     // Upper 4 Bits
45                 str ++;
46                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
47                 *Val |= (*str & 0x3F) << 6;     // Middle 6 Bits
48                 str ++;
49                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
50                 *Val |= (*str & 0x3F);  // Lower 6 Bits
51                 return 3;
52         }
53         
54         // Four Byte
55         if( (*str & 0xF8) == 0xF0 ) {
56                 *Val = (*str & 0x07) << 18;     // Upper 3 Bits
57                 str ++;
58                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
59                 *Val |= (*str & 0x3F) << 12;    // Middle-upper 6 Bits
60                 str ++;
61                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
62                 *Val |= (*str & 0x3F) << 6;     // Middle-lower 6 Bits
63                 str ++;
64                 if( (*str & 0xC0) != 0x80)      return -1;      // Validity check
65                 *Val |= (*str & 0x3F);  // Lower 6 Bits
66                 return 4;
67         }
68         
69         // UTF-8 Doesn't support more than four bytes
70         return 4;
71 }
72
73 /**
74  * \brief Get the UTF-8 character before the 
75  * \
76  */
77 int ReadUTF8Rev(const char *Base, int Offset, uint32_t *Val)
78 {
79          int    len = 0;
80         
81         // Scan backwards for the beginning of the character
82         while( Offset > 0 && (Base[Offset--] & 0xC0) == 0x80 )
83                 len ++;
84         // Invalid string (no beginning)
85         if(Offset == 0 && (Base[Offset] & 0xC0) == 0x80 )
86                 return len;
87         
88         len ++; // First character
89         if( ReadUTF8(Base+Offset, Val) != len ) {
90                 *Val = 0xFFFD;
91         }
92         return len;
93 }
94
95 /**
96  * \brief Write a UTF-8 character sequence to a string
97  * \param buf   Destination buffer (must have at least 4 bytes available)
98  * \param Val   Unicode codepoint to write
99  * \return Number of bytes written
100  * \note Does not NULL terminate the string in \a buf
101  */
102 int WriteUTF8(char *buf, uint32_t Val)
103 {
104         uint8_t *str = (void*)buf;
105         
106         // ASCII
107         if( Val < 128 ) {
108                 if(str) {
109                         *str = Val;
110                 }
111                 return 1;
112         }
113         
114         // Two Byte
115         if( Val < 0x8000 ) {
116                 if(str) {
117                         *str = 0xC0 | (Val >> 6);
118                         str ++;
119                         *str = 0x80 | (Val & 0x3F);
120                 }
121                 return 2;
122         }
123         
124         // Three Byte
125         if( Val < 0x10000 ) {
126                 if(str) {
127                         *str = 0xE0 | (Val >> 12);
128                         str ++;
129                         *str = 0x80 | ((Val >> 6) & 0x3F);
130                         str ++;
131                         *str = 0x80 | (Val & 0x3F);
132                 }
133                 return 3;
134         }
135         
136         // Four Byte
137         if( Val < 0x110000 ) {
138                 if(str) {
139                         *str = 0xF0 | (Val >> 18);
140                         str ++;
141                         *str = 0x80 | ((Val >> 12) & 0x3F);
142                         str ++;
143                         *str = 0x80 | ((Val >> 6) & 0x3F);
144                         str ++;
145                         *str = 0x80 | (Val & 0x3F);
146                 }
147                 return 4;
148         }
149         
150         // UTF-8 Doesn't support more than four bytes
151         return 0;
152 }
153

UCC git Repository :: git.ucc.asn.au