1 /*
2  * Part of WCM Commander
3  * https://github.com/corporateshark/WCMCommander
4  * wcm@linderdaum.com
5  */
6 
7 #include <stdint.h>
8 #include <cstdarg>
9 #include <string>
10 #include <algorithm>
11 
12 #include "string-util.h"
13 
14 static const int BUFFER = 65535;
15 
FindSubstr(const std::vector<unicode_t>::iterator & begin,const std::vector<unicode_t>::iterator & end,const std::vector<unicode_t> & SubStr)16 std::vector<unicode_t>::iterator FindSubstr( const std::vector<unicode_t>::iterator& begin, const std::vector<unicode_t>::iterator& end, const std::vector<unicode_t>& SubStr )
17 {
18 	if ( begin >= end ) { return end; }
19 
20 	return std::search( begin, end, SubStr.begin(), SubStr.end() );
21 }
22 
23 // UTF8 version of the function is in ux_util.cpp
escShellStr(std::vector<unicode_t> & ustr,const unicode_t * src)24 void escShellStr(std::vector<unicode_t>& ustr, const unicode_t* src)
25 {
26 	std::vector<unicode_t> dest;
27 	if(!src)
28 		src=ustr.data();
29 
30 	for ( const unicode_t *s = src; *s; s++ )
31 	{
32         // we could safely escape every char here,
33         // though this would obfuscate diagnostic messages
34 		bool mustEscape = *s<'+'
35 						  || ( *s >= ';' && *s <= '?' )
36 						  || ( *s > 'Z' && *s < 'a' )
37 						  || ( *s >'z' )
38 						  || ( *s == '`' );
39 		if(mustEscape)
40 		{
41 			dest.push_back('\\');
42 		}
43 		dest.push_back(*s);
44 	}
45 	dest.push_back(0);
46 
47 	ustr = dest;
48 }
49 
MakeCommand(const std::vector<unicode_t> & cmd,const unicode_t * FileName)50 std::vector<unicode_t> MakeCommand( const std::vector<unicode_t>& cmd, const unicode_t* FileName )
51 {
52 	std::vector<unicode_t> Result( cmd );
53 	std::vector<unicode_t> Name = new_unicode_str( FileName );
54 	escShellStr(Name);
55 
56 //	bool HasSpaces = StrHaveSpace( Name.data() );
57 
58 	if ( Name.size() && Name.back() == 0 ) { Name.pop_back(); }
59 
60 //	if ( HasSpaces )
61 	{
62 		Name.insert( Name.begin(), '"' );
63 		Name.push_back( '"' );
64 	}
65 
66 	std::vector<unicode_t> Mask;
67 	Mask.push_back( '!' );
68 	Mask.push_back( '.' );
69 	Mask.push_back( '!' );
70 
71 	auto pos = FindSubstr( Result.begin(), Result.end(), Mask );
72 
73 	while ( pos != Result.end() )
74 	{
75 		pos = Result.erase( pos, pos + Mask.size() );
76 		size_t idx = pos - Result.begin();
77 		Result.insert( pos, Name.begin(), Name.end() );
78 		pos = Result.begin() + idx;
79 		pos = FindSubstr( pos + Name.size(), Result.end(), Mask );
80 	}
81 
82 	return Result;
83 }
84 
GetFileExt(const std::string & uri)85 std::string GetFileExt( const std::string& uri )
86 {
87 	// FIXME: Probably non-utf8-proof.
88 	size_t dot = uri.rfind( '.' );
89 	if ( dot == std::string::npos )
90 	{
91 		return std::string();
92 	}
93 	return uri.substr(dot);
94 }
95 
GetFileExt(const unicode_t * uri)96 std::string GetFileExt( const unicode_t* uri )
97 {
98 	if ( !uri ) { return std::string(); }
99 
100 	const unicode_t* ext = find_right_char<unicode_t>( uri, '.' );
101 
102 	if ( !ext || !*ext ) { return std::string(); }
103 
104 	return unicode_to_utf8_string( ext );
105 }
106 
UnicodeToUtf16(const unicode_t * s)107 std::vector<wchar_t> UnicodeToUtf16( const unicode_t* s )
108 {
109 	if ( !s ) { return std::vector<wchar_t>(); }
110 
111 	std::vector<wchar_t> p( unicode_strlen( s ) + 1 );
112 	wchar_t* d;
113 
114 	for ( d = p.data(); *s; s++, d++ ) { *d = *s; }
115 
116 	*d = 0;
117 	return p;
118 }
119 
Utf16ToUnicode(const wchar_t * s)120 std::vector<unicode_t> Utf16ToUnicode( const wchar_t* s )
121 {
122 	std::vector<unicode_t> p( wcslen( s ) + 1 );
123 	unicode_t* d;
124 
125 	for ( d = p.data(); *s; s++, d++ ) { *d = *s; }
126 
127 	*d = 0;
128 	return p;
129 }
130 
widen(const std::string & utf8)131 std::wstring widen( const std::string& utf8 )
132 {
133 #if defined(_WIN32)
134 	int Len = MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), utf8.length(), nullptr, 0);
135 
136 	if ( Len > 0 )
137 	{
138 		wchar_t* Out = (wchar_t*)alloca( Len * sizeof(wchar_t) );
139 
140 		MultiByteToWideChar( CP_UTF8, 0, utf8.c_str(), utf8.length(), Out, Len );
141 
142 		return std::wstring( Out, Len );
143 	}
144 
145 	return std::wstring();
146 #else
147 	return std::wstring( utf8str_to_unicode( utf8 ).data() );
148 #endif
149 }
150 
151 // convert UCS-2 to UTF-8
narrow(const std::wstring & ucs2)152 std::string narrow( const std::wstring& ucs2 )
153 {
154 #if defined(_WIN32)
155 	std::string ret;
156 
157 	int Len = WideCharToMultiByte( CP_UTF8, 0, ucs2.c_str(), ucs2.length(), nullptr, 0, nullptr, nullptr );
158 
159 	if ( Len > 0 )
160 	{
161 		char* Out = (char*)alloca( Len );
162 
163 		WideCharToMultiByte( CP_UTF8, 0, ucs2.c_str(), ucs2.length(), Out, Len, nullptr, nullptr );
164 
165 		return std::string( Out, Len );
166 	}
167 
168 	return std::string();
169 #else
170 	return unicode_to_utf8_string( ucs2.c_str() );
171 #endif
172 }
173 
TruncateToLength(const std::vector<unicode_t> & Str,size_t MaxLength_Chars,bool InsertEllipsis)174 std::vector<unicode_t> TruncateToLength( const std::vector<unicode_t>& Str, size_t MaxLength_Chars, bool InsertEllipsis )
175 {
176 	size_t Length_Chars  = Str.size();
177 
178 	if ( Length_Chars > MaxLength_Chars )
179 	{
180 		std::vector<unicode_t> Result = std::vector<unicode_t>( Str.begin() + ( Length_Chars - MaxLength_Chars ), Str.end() );
181 
182 		// add ... at the beginning
183 		if ( InsertEllipsis )
184 		{
185 			const unicode_t Prefix[] = { '.', '.', '.' };
186 			Result.insert( Result.begin(), Prefix, Prefix + 3 );
187 		}
188 
189 		return Result;
190 	}
191 
192 	return Str;
193 }
194 
ToString(uint64_t FromUInt64)195 inline std::string ToString( uint64_t FromUInt64 )
196 {
197 	char Buffer[ BUFFER ];
198 
199 #ifdef OS_WINDOWS
200 #	if _MSC_VER >= 1400
201 	_ui64toa_s( FromUInt64, Buffer, sizeof(Buffer)-1, 10 );
202 #	else
203 	_ui64toa( FromUInt64, Buffer, 10 );
204 #	endif
205 #else
206 	Lsnprintf( Buffer, sizeof(Buffer)-1, "%" PRIu64, FromUInt64 );
207 #endif
208 
209 	return std::string( Buffer );
210 }
211 
ToString(int64_t FromInt64)212 std::string ToString( int64_t FromInt64 )
213 {
214 	char Buffer[ BUFFER ];
215 
216 #ifdef OS_WINDOWS
217 #	if _MSC_VER >= 1400
218 	_i64toa_s( FromInt64, Buffer, sizeof(Buffer)-1, 10 );
219 #	else
220 	_i64toa( FromInt64, Buffer, 10 );
221 #	endif
222 #else
223 	Lsnprintf( Buffer, sizeof(Buffer)-1, "%" PRIi64, FromInt64 );
224 #endif
225 
226 	return std::string( Buffer );
227 }
228 
ToString(int FromInt)229 std::string ToString( int FromInt )
230 {
231 	char Buffer[ BUFFER ];
232 
233 	Lsnprintf( Buffer, sizeof(Buffer) - 1, "%i", FromInt );
234 
235 	return std::string( Buffer );
236 }
237 
238 // convert unsigned integer 12345678 to "12 345 678"
ToStringGrouped(uint64_t FromUInt64,const char * GroupSeparator)239 std::string ToStringGrouped( uint64_t FromUInt64, const char* GroupSeparator )
240 {
241 	std::string Result = ToString( FromUInt64 );
242 
243 	for ( int Pos = static_cast<int>( Result.length() ) - 3; Pos > 0; Pos -= 3 )
244 	{
245 		Result.insert( Pos, GroupSeparator );
246 	}
247 
248 	return Result;
249 }
250 
GetFormattedString(const char * Pattern,...)251 std::string GetFormattedString( const char* Pattern, ... )
252 {
253 	char Buffer[ BUFFER ];
254 
255 	va_list p;
256 	va_start( p, Pattern );
257 
258 	Lvsnprintf( Buffer, sizeof(Buffer) - 1, Pattern, p );
259 
260 	va_end( p );
261 
262 	return std::string( Buffer );
263 }
264