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