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