1 //-----------------------------------------------------------------------------
2 // Project : SDK Core
3 //
4 // Category : Helpers
5 // Filename : pluginterfaces/base/ustring.cpp
6 // Created by : Steinberg, 12/2005
7 // Description : UTF-16 String class
8 //
9 //-----------------------------------------------------------------------------
10 // This file is part of a Steinberg SDK. It is subject to the license terms
11 // in the LICENSE file found in the top-level directory of this distribution
12 // and at www.steinberg.net/sdklicenses.
13 // No part of the SDK, including this file, may be copied, modified, propagated,
14 // or distributed except according to the terms contained in the LICENSE file.
15 //-----------------------------------------------------------------------------
16
17 #include "ustring.h"
18
19 #if SMTG_OS_WINDOWS
20 #include <stdio.h>
21 #pragma warning (disable : 4996)
22
23 #elif SMTG_OS_MACOS
24 #include <CoreFoundation/CoreFoundation.h>
25
26 #elif SMTG_OS_LINUX
27 #include <cstring>
28 #include <string>
29 #include <codecvt>
30 #include <sstream>
31 #include <locale>
32
33 #include <wctype.h>
34 #include <wchar.h>
35
36 #endif
37
38 //------------------------------------------------------------------------
39 namespace Steinberg {
40
41 //------------------------------------------------------------------------
42 #if SMTG_OS_LINUX
43
44 //------------------------------------------------------------------------
45 namespace {
46
47 using Converter = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>;
48
49 //------------------------------------------------------------------------
converter()50 Converter& converter ()
51 {
52 static Converter instance;
53 return instance;
54 }
55
56 //------------------------------------------------------------------------
57 } // anonymous
58
59 //------------------------------------------------------------------------
60 #endif // SMTG_OS_LINUX
61
62 //------------------------------------------------------------------------
63 /** Copy strings of different character width. */
64 //------------------------------------------------------------------------
65 template <class TDstChar, class TSrcChar>
StringCopy(TDstChar * dst,int32 dstSize,const TSrcChar * src,int32 srcSize=-1)66 void StringCopy (TDstChar* dst, int32 dstSize, const TSrcChar* src, int32 srcSize = -1)
67 {
68 int32 count = dstSize;
69 if (srcSize >= 0 && srcSize < dstSize)
70 count = srcSize;
71 for (int32 i = 0; i < count; i++)
72 {
73 dst[i] = (TDstChar)src[i];
74 if (src[i] == 0)
75 break;
76 }
77 dst[dstSize - 1] = 0;
78 }
79
80 //------------------------------------------------------------------------
81 /** Find length of null-terminated string. */
82 //------------------------------------------------------------------------
83 template <class TSrcChar>
StringLength(const TSrcChar * src,int32 srcSize=-1)84 int32 StringLength (const TSrcChar* src, int32 srcSize = -1)
85 {
86 if (srcSize == 0)
87 return 0;
88 int32 length = 0;
89 while (src[length])
90 {
91 length++;
92 if (srcSize > 0 && length >= srcSize)
93 break;
94 }
95 return length;
96 }
97
98 //------------------------------------------------------------------------
99 // UString
100 //------------------------------------------------------------------------
getLength() const101 int32 UString::getLength () const
102 {
103 return StringLength<char16> (thisBuffer, thisSize);
104 }
105
106 //------------------------------------------------------------------------
assign(const char16 * src,int32 srcSize)107 UString& UString::assign (const char16* src, int32 srcSize)
108 {
109 StringCopy<char16, char16> (thisBuffer, thisSize, src, srcSize);
110 return *this;
111 }
112
113 //------------------------------------------------------------------------
append(const char16 * src,int32 srcSize)114 UString& UString::append (const char16* src, int32 srcSize)
115 {
116 int32 length = getLength ();
117 StringCopy<char16, char16> (thisBuffer + length, thisSize - length, src, srcSize);
118 return *this;
119 }
120
121 //------------------------------------------------------------------------
copyTo(char16 * dst,int32 dstSize) const122 const UString& UString::copyTo (char16* dst, int32 dstSize) const
123 {
124 StringCopy<char16, char16> (dst, dstSize, thisBuffer, thisSize);
125 return *this;
126 }
127
128 //------------------------------------------------------------------------
fromAscii(const char * src,int32 srcSize)129 UString& UString::fromAscii (const char* src, int32 srcSize)
130 {
131 StringCopy<char16, char> (thisBuffer, thisSize, src, srcSize);
132 return *this;
133 }
134
135 //------------------------------------------------------------------------
toAscii(char * dst,int32 dstSize) const136 const UString& UString::toAscii (char* dst, int32 dstSize) const
137 {
138 StringCopy<char, char16> (dst, dstSize, thisBuffer, thisSize);
139 return *this;
140 }
141
142 //------------------------------------------------------------------------
scanFloat(double & value) const143 bool UString::scanFloat (double& value) const
144 {
145 #if SMTG_OS_WINDOWS
146 return swscanf ((const wchar_t*)thisBuffer, L"%lf", &value) != -1;
147
148 #elif TARGET_API_MAC_CARBON
149 CFStringRef cfStr = CFStringCreateWithBytes (0, (const UInt8 *)thisBuffer, getLength () * 2, kCFStringEncodingUTF16, false);
150 if (cfStr)
151 {
152 value = CFStringGetDoubleValue (cfStr);
153 CFRelease (cfStr);
154 return true;
155 }
156 return false;
157
158 #elif SMTG_OS_LINUX
159 auto str = converter ().to_bytes (thisBuffer);
160 return sscanf (str.data (), "%lf", &value) == 1;
161
162 #else
163 #warning Implement me
164 // implement me!
165 return false;
166 #endif
167 }
168
169 //------------------------------------------------------------------------
printFloat(double value,int32 precision)170 bool UString::printFloat (double value, int32 precision)
171 {
172 #if SMTG_OS_WINDOWS
173 return swprintf ((wchar_t*)thisBuffer, L"%.*lf", precision, value) != -1;
174 #elif SMTG_OS_MACOS
175 bool result = false;
176 CFStringRef cfStr = CFStringCreateWithFormat (0, 0, CFSTR("%.*lf"), precision, value);
177 if (cfStr)
178 {
179 memset (thisBuffer, 0, thisSize);
180 CFRange range = {0, CFStringGetLength (cfStr)};
181 CFStringGetBytes (cfStr, range, kCFStringEncodingUTF16, 0, false, (UInt8*)thisBuffer, thisSize, 0);
182 CFRelease (cfStr);
183 return true;
184 }
185 return result;
186 #elif SMTG_OS_LINUX
187 auto utf8Buffer = reinterpret_cast<char*> (thisBuffer);
188 auto len = snprintf (utf8Buffer, thisSize, "%.*lf", precision, value);
189 if (len > 0)
190 {
191 auto utf16Buffer = reinterpret_cast<char16*> (thisBuffer);
192 utf16Buffer[len] = 0;
193 while (--len >= 0)
194 {
195 utf16Buffer[len] = utf8Buffer[len];
196 }
197 return true;
198 }
199 return false;
200 #else
201 #warning Implement me
202 // implement me!
203 return false;
204 #endif
205 }
206
207 //------------------------------------------------------------------------
scanInt(int64 & value) const208 bool UString::scanInt (int64& value) const
209 {
210 #if SMTG_OS_WINDOWS
211 return swscanf ((const wchar_t*)thisBuffer, L"%I64d", &value) != -1;
212
213 #elif SMTG_OS_MACOS
214 CFStringRef cfStr = CFStringCreateWithBytes (0, (const UInt8 *)thisBuffer, getLength () * 2, kCFStringEncodingUTF16, false);
215 if (cfStr)
216 {
217 value = CFStringGetIntValue (cfStr);
218 CFRelease (cfStr);
219 return true;
220 }
221 return false;
222
223 #elif SMTG_OS_LINUX
224 auto str = converter ().to_bytes (thisBuffer);
225 return sscanf (str.data (), "%lld", &value) == 1;
226
227 #else
228 #warning Implement me
229 // implement me!
230 return false;
231 #endif
232 }
233
234 //------------------------------------------------------------------------
printInt(int64 value)235 bool UString::printInt (int64 value)
236 {
237 #if SMTG_OS_WINDOWS
238 return swprintf ((wchar_t*)thisBuffer, L"%I64d", value) != -1;
239
240 #elif SMTG_OS_MACOS
241 CFStringRef cfStr = CFStringCreateWithFormat (0, 0, CFSTR("%lld"), value);
242 if (cfStr)
243 {
244 memset (thisBuffer, 0, thisSize);
245 CFRange range = {0, CFStringGetLength (cfStr)};
246 CFStringGetBytes (cfStr, range, kCFStringEncodingUTF16, 0, false, (UInt8*)thisBuffer, thisSize, 0);
247 CFRelease (cfStr);
248 return true;
249 }
250 return false;
251 #elif SMTG_OS_LINUX
252 auto utf8Buffer = reinterpret_cast<char*> (thisBuffer);
253 auto len = snprintf (utf8Buffer, thisSize, "%lld", value);
254 if (len > 0)
255 {
256 auto utf16Buffer = reinterpret_cast<char16*> (thisBuffer);
257 utf16Buffer[len] = 0;
258 while (--len >= 0)
259 {
260 utf16Buffer[len] = utf8Buffer[len];
261 }
262 return true;
263 }
264 return false;
265
266 #else
267 #warning Implement me
268 // implement me!
269 return false;
270 #endif
271 }
272 } // namespace Steinberg
273