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

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