Doxygen
Loading...
Searching...
No Matches
utf8.cpp
Go to the documentation of this file.
1/******************************************************************************
2 *
3 * Copyright (C) 1997-2021 by Dimitri van Heesch.
4 *
5 * Permission to use, copy, modify, and distribute this software and its
6 * documentation under the terms of the GNU General Public License is hereby
7 * granted. No representations are made about the suitability of this software
8 * for any purpose. It is provided "as is" without express or implied warranty.
9 * See the GNU General Public License for more details.
10 *
11 * Documents produced by Doxygen are derivative works derived from the
12 * input used in their production; they are not affected by this license.
13 *
14 */
15
16// own header
17#include "utf8.h"
18
19// standard includes
20#include <cstdint>
21
22// other includes
23#include "caseconvert.h"
24#include "portable.h"
25#include "textstream.h"
26
27uint8_t getUTF8CharNumBytes(char c)
28{
29 uint8_t num=1;
30 unsigned char uc = static_cast<unsigned char>(c);
31 if (uc>=0x80u) // multibyte character
32 {
33 if ((uc&0xE0u)==0xC0u)
34 {
35 num=2; // 110x.xxxx: 2 byte character
36 }
37 if ((uc&0xF0u)==0xE0u)
38 {
39 num=3; // 1110.xxxx: 3 byte character
40 }
41 if ((uc&0xF8u)==0xF0u)
42 {
43 num=4; // 1111.0xxx: 4 byte character
44 }
45 if ((uc&0xFCu)==0xF8u)
46 {
47 num=5; // 1111.10xx: 5 byte character
48 }
49 if ((uc&0xFEu)==0xFCu)
50 {
51 num=6; // 1111.110x: 6 byte character
52 }
53 }
54 return num;
55}
56
57//! Decodes a given input of utf8 data to a unicode code point
58//! given the number of bytes it's made of
59static inline uint32_t decode_utf8( const char* data , int numBytes ) noexcept
60{
61 uint32_t cp = static_cast<unsigned char>(*data);
62 if (numBytes>1)
63 {
64 cp &= 0x7F >> numBytes; // Mask out the header bits
65 for (int i=1 ; i<numBytes ; i++)
66 {
67 cp = (cp<<6) | (static_cast<unsigned char>(data[i])&0x3F);
68 }
69 }
70 return cp;
71}
72
73static inline uint32_t convertUTF8CharToUnicode(const char *s,size_t bytesLeft,int &len)
74{
75 if (s==nullptr || bytesLeft==0)
76 {
77 len=0;
78 return 0;
79 }
80 unsigned char uc = static_cast<unsigned char>(*s);
81 if (uc<128) // ASCII case
82 {
83 len=1;
84 return uc;
85 }
86 switch (bytesLeft)
87 {
88 default:
89 if ((uc&0xFEu)==0xFCu)// 1111110X six bytes
90 {
91 len=6;
92 return decode_utf8(s,len);
93 }
94 // fall through
95 case 5:
96 if ((uc&0xFCu)==0xF8u) // 111110XX five bytes
97 {
98 len=5;
99 return decode_utf8(s,len);
100 }
101 // fall through
102 case 4:
103 if ((uc&0xF8u)==0xF0u) // 11110XXX four bytes
104 {
105 len=4;
106 return decode_utf8(s,len);
107 }
108 // fall through
109 case 3:
110 if ((uc&0xF0u)==0xE0u) // 1110XXXX three bytes
111 {
112 len=3;
113 return decode_utf8(s,len);
114 }
115 // fall through
116 case 2:
117 if ((uc&0xE0u)==0xC0u) // 110XXXXX two bytes
118 {
119 len=2;
120 return decode_utf8(s,len);
121 }
122 // fall through
123 case 1:
124 {
125 len=1;
126 return uc;
127 }
128 }
129}
130
131std::string getUTF8CharAt(const std::string &input,size_t pos)
132{
133 if (input.length()<=pos) return std::string();
134 int numBytes=getUTF8CharNumBytes(input[pos]);
135 if (input.length()<pos+numBytes) return std::string();
136 return input.substr(pos,numBytes);
137}
138
139uint32_t getUnicodeForUTF8CharAt(const std::string &input,size_t pos)
140{
141 std::string charS = getUTF8CharAt(input,pos);
142 int len=0;
143 return convertUTF8CharToUnicode(charS.c_str(),charS.length(),len);
144}
145
146static inline char asciiToLower(uint32_t code)
147{
148 return code>='A' && code<='Z' ? static_cast<char>(code+'a'-'A') : static_cast<char>(code);
149}
150
151static inline char asciiToUpper(uint32_t code)
152{
153 return code>='a' && code<='z' ? static_cast<char>(code+'A'-'a') : static_cast<char>(code);
154}
155
156static inline std::string caseConvert(const std::string &input,
157 char (*asciiConversionFunc)(uint32_t code),
158 const char *(*conversionFunc)(uint32_t code))
159{
160 uint32_t code=0;
161 std::string result;
162 result.reserve(input.length()); // assume all ASCII characters
163 int len=0;
164 size_t bytesLeft = input.length();
165 const char *p = input.c_str();
166 while ((code=convertUTF8CharToUnicode(p,bytesLeft,len)))
167 {
168 if (code<128) // ASCII case
169 {
170 char c = asciiConversionFunc(code);
171 result+=c;
172 }
173 else // generic case
174 {
175 const char *conv = conversionFunc(code);
176 if (conv==nullptr) // no difference between lower and upper case
177 {
178 result.append(p,len);
179 }
180 else // replace the input character with the conversion result
181 {
182 result.append(conv);
183 }
184 }
185 p+=len;
186 bytesLeft-=len;
187 }
188 return result;
189}
190
191std::string convertUTF8ToLower(const std::string &input)
192{
194}
195
196std::string convertUTF8ToUpper(const std::string &input)
197{
199}
200
201const char *writeUTF8Char(TextStream &t,const char *s)
202{
203 if (s==nullptr) return nullptr;
204 uint8_t len = getUTF8CharNumBytes(*s);
205 for (uint8_t i=0;i<len;i++)
206 {
207 if (s[i]==0) // detect premature end of string (due to invalid UTF8 char)
208 {
209 len=i;
210 }
211 }
212 t.write(s,len);
213 return s+len;
214}
215
216bool lastUTF8CharIsMultibyte(const std::string &input)
217{
218 // last byte is part of a multibyte UTF8 char if bit 8 is set and bit 7 is not
219 return !input.empty() && (static_cast<unsigned char>(input[input.length()-1])&0xC0)==0x80;
220}
221
222bool isUTF8CharUpperCase(const std::string &input,size_t pos)
223{
224 if (input.length()<=pos) return false;
225 int len=0;
226 // turn the UTF8 character at position pos into a unicode value
227 uint32_t code = convertUTF8CharToUnicode(input.c_str()+pos,input.length()-pos,len);
228 // check if the character can be converted to lower case, if so it was an upper case character
229 return convertUnicodeToLower(code)!=nullptr;
230}
231
232int isUTF8NonBreakableSpace(const char *input)
233{
234 return (static_cast<unsigned char>(input[0])==0xC2 &&
235 static_cast<unsigned char>(input[1])==0xA0) ? 2 : 0;
236}
237
238bool isUTF8PunctuationCharacter(uint32_t unicode)
239{
240 bool b = isPunctuationCharacter(unicode);
241 return b;
242}
243
244bool transcodeCharacterStringToUTF8(std::string &input, const char *inputEncoding)
245{
246 const char *outputEncoding = "UTF-8";
247 if (inputEncoding==nullptr || dstricmp(inputEncoding,outputEncoding)==0) return true;
248 size_t inputSize=input.length();
249 size_t outputSize=inputSize*4;
250 DString output(outputSize, DString::ExplicitSize);
251 void *cd = portable_iconv_open(outputEncoding,inputEncoding);
252 if (cd==reinterpret_cast<void *>(-1))
253 {
254 return false;
255 }
256 bool ok=true;
257 size_t iLeft=inputSize;
258 size_t oLeft=outputSize;
259 const char *inputPtr = input.data();
260 char *outputPtr = output.rawData();
261 if (!portable_iconv(cd, &inputPtr, &iLeft, &outputPtr, &oLeft))
262 {
263 outputSize-=static_cast<int>(oLeft);
264 output.resize(outputSize);
265 output.at(outputSize)='\0';
266 // replace input
267 input=output.str();
268 //printf("iconv: input size=%d output size=%d\n[%s]\n",size,newSize,qPrint(srcBuf));
269 }
270 else
271 {
272 ok=false;
273 }
275 return ok;
276}
277
bool isPunctuationCharacter(uint32_t code)
const char * convertUnicodeToUpper(uint32_t code)
Definition caseconvert.h:12
const char * convertUnicodeToLower(uint32_t code)
A String class for use with Doxygen wrapping std::string and adding some additional functionality off...
Definition dstring.h:84
void resize(size_t newlen)
Definition dstring.h:209
char * rawData()
Returns a writable pointer to the data.
Definition dstring.h:166
char & at(size_t i)
Returns a reference to the character at index i.
Definition dstring.h:686
@ ExplicitSize
Definition dstring.h:131
const std::string & str() const
Definition dstring.h:645
Text streaming class that buffers data.
Definition textstream.h:36
void write(const char *buf, size_t len)
Adds a array of character to the stream.
Definition textstream.h:204
static char asciiToLower(char in)
Definition debug.cpp:89
int dstricmp(const char *s1, const char *s2)
Definition dstring.cpp:444
Portable versions of functions that are platform dependent.
int portable_iconv_close(void *cd)
size_t portable_iconv(void *cd, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft)
void * portable_iconv_open(const char *tocode, const char *fromcode)
std::string convertUTF8ToUpper(const std::string &input)
Converts the input string into a upper case version, also taking into account non-ASCII characters th...
Definition utf8.cpp:196
static char asciiToLower(uint32_t code)
Definition utf8.cpp:146
bool isUTF8CharUpperCase(const std::string &input, size_t pos)
Returns true iff the input string at byte position pos holds an upper case character.
Definition utf8.cpp:222
bool transcodeCharacterStringToUTF8(std::string &input, const char *inputEncoding)
Recodes the input string from the given input encoding to UTF8.
Definition utf8.cpp:244
bool isUTF8PunctuationCharacter(uint32_t unicode)
Check if the given Unicode character represents a punctuation character.
Definition utf8.cpp:238
static uint32_t decode_utf8(const char *data, int numBytes) noexcept
Definition utf8.cpp:59
static uint32_t convertUTF8CharToUnicode(const char *s, size_t bytesLeft, int &len)
Definition utf8.cpp:73
static char asciiToUpper(uint32_t code)
Definition utf8.cpp:151
static std::string caseConvert(const std::string &input, char(*asciiConversionFunc)(uint32_t code), const char *(*conversionFunc)(uint32_t code))
Definition utf8.cpp:156
uint32_t getUnicodeForUTF8CharAt(const std::string &input, size_t pos)
Returns the 32bit Unicode value matching character at byte position pos in the UTF8 encoded input.
Definition utf8.cpp:139
bool lastUTF8CharIsMultibyte(const std::string &input)
Returns true iff the last character in input is a multibyte character.
Definition utf8.cpp:216
int isUTF8NonBreakableSpace(const char *input)
Check if the first character pointed at by input is a non-breakable whitespace character.
Definition utf8.cpp:232
std::string convertUTF8ToLower(const std::string &input)
Converts the input string into a lower case version, also taking into account non-ASCII characters th...
Definition utf8.cpp:191
uint8_t getUTF8CharNumBytes(char c)
Returns the number of bytes making up a single UTF8 character given the first byte in the sequence.
Definition utf8.cpp:27
std::string getUTF8CharAt(const std::string &input, size_t pos)
Returns the UTF8 character found at byte position pos in the input string.
Definition utf8.cpp:131
const char * writeUTF8Char(TextStream &t, const char *s)
Writes the UTF8 character pointed to by s to stream t and returns a pointer to the next character.
Definition utf8.cpp:201
Various UTF8 related helper functions.