/src/mozilla-central/gfx/vr/openvr/src/strtools_public.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //========= Copyright Valve Corporation ============// |
2 | | #include "strtools_public.h" |
3 | | #include <string.h> |
4 | | #include <stdio.h> |
5 | | #include <stdlib.h> |
6 | | #include <sstream> |
7 | | #include <iostream> |
8 | | |
9 | | //----------------------------------------------------------------------------- |
10 | | // Purpose: |
11 | | //----------------------------------------------------------------------------- |
12 | | bool StringHasPrefix( const std::string & sString, const std::string & sPrefix ) |
13 | 0 | { |
14 | 0 | return 0 == strnicmp( sString.c_str(), sPrefix.c_str(), sPrefix.length() ); |
15 | 0 | } |
16 | | |
17 | | bool StringHasPrefixCaseSensitive( const std::string & sString, const std::string & sPrefix ) |
18 | 0 | { |
19 | 0 | return 0 == strncmp( sString.c_str(), sPrefix.c_str(), sPrefix.length() ); |
20 | 0 | } |
21 | | |
22 | | |
23 | | bool StringHasSuffix( const std::string &sString, const std::string &sSuffix ) |
24 | 0 | { |
25 | 0 | size_t cStrLen = sString.length(); |
26 | 0 | size_t cSuffixLen = sSuffix.length(); |
27 | 0 |
|
28 | 0 | if ( cSuffixLen > cStrLen ) |
29 | 0 | return false; |
30 | 0 | |
31 | 0 | std::string sStringSuffix = sString.substr( cStrLen - cSuffixLen, cSuffixLen ); |
32 | 0 |
|
33 | 0 | return 0 == stricmp( sStringSuffix.c_str(), sSuffix.c_str() ); |
34 | 0 | } |
35 | | |
36 | | bool StringHasSuffixCaseSensitive( const std::string &sString, const std::string &sSuffix ) |
37 | 0 | { |
38 | 0 | size_t cStrLen = sString.length(); |
39 | 0 | size_t cSuffixLen = sSuffix.length(); |
40 | 0 |
|
41 | 0 | if ( cSuffixLen > cStrLen ) |
42 | 0 | return false; |
43 | 0 | |
44 | 0 | std::string sStringSuffix = sString.substr( cStrLen - cSuffixLen, cSuffixLen ); |
45 | 0 |
|
46 | 0 | return 0 == strncmp( sStringSuffix.c_str(), sSuffix.c_str(),cSuffixLen ); |
47 | 0 | } |
48 | | |
49 | | //----------------------------------------------------------------------------- |
50 | | // Purpose: |
51 | | //----------------------------------------------------------------------------- |
52 | | std::string UTF16to8(const wchar_t * in) |
53 | 0 | { |
54 | 0 | std::string out; |
55 | 0 | unsigned int codepoint = 0; |
56 | 0 | for ( ; in && *in != 0; ++in ) |
57 | 0 | { |
58 | 0 | if (*in >= 0xd800 && *in <= 0xdbff) |
59 | 0 | codepoint = ((*in - 0xd800) << 10) + 0x10000; |
60 | 0 | else |
61 | 0 | { |
62 | 0 | if (*in >= 0xdc00 && *in <= 0xdfff) |
63 | 0 | codepoint |= *in - 0xdc00; |
64 | 0 | else |
65 | 0 | codepoint = *in; |
66 | 0 |
|
67 | 0 | if (codepoint <= 0x7f) |
68 | 0 | out.append(1, static_cast<char>(codepoint)); |
69 | 0 | else if (codepoint <= 0x7ff) |
70 | 0 | { |
71 | 0 | out.append(1, static_cast<char>(0xc0 | ((codepoint >> 6) & 0x1f))); |
72 | 0 | out.append(1, static_cast<char>(0x80 | (codepoint & 0x3f))); |
73 | 0 | } |
74 | 0 | else if (codepoint <= 0xffff) |
75 | 0 | { |
76 | 0 | out.append(1, static_cast<char>(0xe0 | ((codepoint >> 12) & 0x0f))); |
77 | 0 | out.append(1, static_cast<char>(0x80 | ((codepoint >> 6) & 0x3f))); |
78 | 0 | out.append(1, static_cast<char>(0x80 | (codepoint & 0x3f))); |
79 | 0 | } |
80 | 0 | else |
81 | 0 | { |
82 | 0 | out.append(1, static_cast<char>(0xf0 | ((codepoint >> 18) & 0x07))); |
83 | 0 | out.append(1, static_cast<char>(0x80 | ((codepoint >> 12) & 0x3f))); |
84 | 0 | out.append(1, static_cast<char>(0x80 | ((codepoint >> 6) & 0x3f))); |
85 | 0 | out.append(1, static_cast<char>(0x80 | (codepoint & 0x3f))); |
86 | 0 | } |
87 | 0 | codepoint = 0; |
88 | 0 | } |
89 | 0 | } |
90 | 0 | return out; |
91 | 0 | } |
92 | | |
93 | | std::wstring UTF8to16(const char * in) |
94 | 0 | { |
95 | 0 | std::wstring out; |
96 | 0 | unsigned int codepoint = 0; |
97 | 0 | int following = 0; |
98 | 0 | for ( ; in && *in != 0; ++in ) |
99 | 0 | { |
100 | 0 | unsigned char ch = *in; |
101 | 0 | if (ch <= 0x7f) |
102 | 0 | { |
103 | 0 | codepoint = ch; |
104 | 0 | following = 0; |
105 | 0 | } |
106 | 0 | else if (ch <= 0xbf) |
107 | 0 | { |
108 | 0 | if (following > 0) |
109 | 0 | { |
110 | 0 | codepoint = (codepoint << 6) | (ch & 0x3f); |
111 | 0 | --following; |
112 | 0 | } |
113 | 0 | } |
114 | 0 | else if (ch <= 0xdf) |
115 | 0 | { |
116 | 0 | codepoint = ch & 0x1f; |
117 | 0 | following = 1; |
118 | 0 | } |
119 | 0 | else if (ch <= 0xef) |
120 | 0 | { |
121 | 0 | codepoint = ch & 0x0f; |
122 | 0 | following = 2; |
123 | 0 | } |
124 | 0 | else |
125 | 0 | { |
126 | 0 | codepoint = ch & 0x07; |
127 | 0 | following = 3; |
128 | 0 | } |
129 | 0 | if (following == 0) |
130 | 0 | { |
131 | 0 | if (codepoint > 0xffff) |
132 | 0 | { |
133 | 0 | out.append(1, static_cast<wchar_t>(0xd800 + (codepoint >> 10))); |
134 | 0 | out.append(1, static_cast<wchar_t>(0xdc00 + (codepoint & 0x03ff))); |
135 | 0 | } |
136 | 0 | else |
137 | 0 | out.append(1, static_cast<wchar_t>(codepoint)); |
138 | 0 | codepoint = 0; |
139 | 0 | } |
140 | 0 | } |
141 | 0 | return out; |
142 | 0 | } |
143 | | |
144 | | |
145 | | void strcpy_safe( char *pchBuffer, size_t unBufferSizeBytes, const char *pchSource ) |
146 | 0 | { |
147 | 0 | strncpy( pchBuffer, pchSource, unBufferSizeBytes - 1 ); |
148 | 0 | pchBuffer[unBufferSizeBytes - 1] = '\0'; |
149 | 0 | } |
150 | | |
151 | | |
152 | | // -------------------------------------------------------------------- |
153 | | // Purpose: converts a string to upper case |
154 | | // -------------------------------------------------------------------- |
155 | | std::string StringToUpper( const std::string & sString ) |
156 | 0 | { |
157 | 0 | std::string sOut; |
158 | 0 | sOut.reserve( sString.size() + 1 ); |
159 | 0 | for( std::string::const_iterator i = sString.begin(); i != sString.end(); i++ ) |
160 | 0 | { |
161 | 0 | sOut.push_back( (char)toupper( *i ) ); |
162 | 0 | } |
163 | 0 |
|
164 | 0 | return sOut; |
165 | 0 | } |
166 | | |
167 | | |
168 | | // -------------------------------------------------------------------- |
169 | | // Purpose: converts a string to lower case |
170 | | // -------------------------------------------------------------------- |
171 | | std::string StringToLower( const std::string & sString ) |
172 | 0 | { |
173 | 0 | std::string sOut; |
174 | 0 | sOut.reserve( sString.size() + 1 ); |
175 | 0 | for( std::string::const_iterator i = sString.begin(); i != sString.end(); i++ ) |
176 | 0 | { |
177 | 0 | sOut.push_back( (char)tolower( *i ) ); |
178 | 0 | } |
179 | 0 |
|
180 | 0 | return sOut; |
181 | 0 | } |
182 | | |
183 | | |
184 | | uint32_t ReturnStdString( const std::string & sValue, char *pchBuffer, uint32_t unBufferLen ) |
185 | 0 | { |
186 | 0 | uint32_t unLen = (uint32_t)sValue.length() + 1; |
187 | 0 | if( !pchBuffer || !unBufferLen ) |
188 | 0 | return unLen; |
189 | 0 | |
190 | 0 | if( unBufferLen < unLen ) |
191 | 0 | { |
192 | 0 | pchBuffer[0] = '\0'; |
193 | 0 | } |
194 | 0 | else |
195 | 0 | { |
196 | 0 | memcpy( pchBuffer, sValue.c_str(), unLen ); |
197 | 0 | } |
198 | 0 |
|
199 | 0 | return unLen; |
200 | 0 | } |
201 | | |
202 | | // Commented out by Mozilla, please see README.mozilla |
203 | | /** Returns a std::string from a uint64_t */ |
204 | | /* |
205 | | std::string Uint64ToString( uint64_t ulValue ) |
206 | | { |
207 | | char buf[ 22 ]; |
208 | | #if defined( _WIN32 ) |
209 | | sprintf_s( buf, "%llu", ulValue ); |
210 | | #else |
211 | | snprintf( buf, sizeof( buf ), "%llu", (long long unsigned int ) ulValue ); |
212 | | #endif |
213 | | return buf; |
214 | | } |
215 | | */ |
216 | | |
217 | | /** returns a uint64_t from a string */ |
218 | | uint64_t StringToUint64( const std::string & sValue ) |
219 | 0 | { |
220 | 0 | return strtoull( sValue.c_str(), NULL, 0 ); |
221 | 0 | } |
222 | | |
223 | | //----------------------------------------------------------------------------- |
224 | | // Purpose: Helper for converting a numeric value to a hex digit, value should be 0-15. |
225 | | //----------------------------------------------------------------------------- |
226 | | char cIntToHexDigit( int nValue ) |
227 | 0 | { |
228 | 0 | //Assert( nValue >= 0 && nValue <= 15 ); |
229 | 0 | return "0123456789ABCDEF"[ nValue & 15 ]; |
230 | 0 | } |
231 | | |
232 | | //----------------------------------------------------------------------------- |
233 | | // Purpose: Helper for converting a hex char value to numeric, return -1 if the char |
234 | | // is not a valid hex digit. |
235 | | //----------------------------------------------------------------------------- |
236 | | int iHexCharToInt( char cValue ) |
237 | 0 | { |
238 | 0 | int32_t iValue = cValue; |
239 | 0 | if ( (uint32_t)( iValue - '0' ) < 10 ) |
240 | 0 | return iValue - '0'; |
241 | 0 | |
242 | 0 | iValue |= 0x20; |
243 | 0 | if ( (uint32_t)( iValue - 'a' ) < 6 ) |
244 | 0 | return iValue - 'a' + 10; |
245 | 0 | |
246 | 0 | return -1; |
247 | 0 | } |
248 | | |
249 | | //----------------------------------------------------------------------------- |
250 | | // Purpose: Internal implementation of encode, works in the strict RFC manner, or |
251 | | // with spaces turned to + like HTML form encoding. |
252 | | //----------------------------------------------------------------------------- |
253 | | void V_URLEncodeInternal( char *pchDest, int nDestLen, const char *pchSource, int nSourceLen, bool bUsePlusForSpace ) |
254 | 0 | { |
255 | 0 | //AssertMsg( nDestLen > 3*nSourceLen, "Target buffer for V_URLEncode should be 3x source length, plus one for terminating null\n" ); |
256 | 0 | |
257 | 0 | int iDestPos = 0; |
258 | 0 | for ( int i=0; i < nSourceLen; ++i ) |
259 | 0 | { |
260 | 0 | // worst case we need 3 additional chars |
261 | 0 | if( (iDestPos+3) > nDestLen ) |
262 | 0 | { |
263 | 0 | pchDest[0] = '\0'; |
264 | 0 | // AssertMsg( false, "Target buffer too short\n" ); |
265 | 0 | return; |
266 | 0 | } |
267 | 0 | |
268 | 0 | // We allow only a-z, A-Z, 0-9, period, underscore, and hyphen to pass through unescaped. |
269 | 0 | // These are the characters allowed by both the original RFC 1738 and the latest RFC 3986. |
270 | 0 | // Current specs also allow '~', but that is forbidden under original RFC 1738. |
271 | 0 | if ( !( pchSource[i] >= 'a' && pchSource[i] <= 'z' ) && !( pchSource[i] >= 'A' && pchSource[i] <= 'Z' ) && !(pchSource[i] >= '0' && pchSource[i] <= '9' ) |
272 | 0 | && pchSource[i] != '-' && pchSource[i] != '_' && pchSource[i] != '.' |
273 | 0 | ) |
274 | 0 | { |
275 | 0 | if ( bUsePlusForSpace && pchSource[i] == ' ' ) |
276 | 0 | { |
277 | 0 | pchDest[iDestPos++] = '+'; |
278 | 0 | } |
279 | 0 | else |
280 | 0 | { |
281 | 0 | pchDest[iDestPos++] = '%'; |
282 | 0 | uint8_t iValue = pchSource[i]; |
283 | 0 | if ( iValue == 0 ) |
284 | 0 | { |
285 | 0 | pchDest[iDestPos++] = '0'; |
286 | 0 | pchDest[iDestPos++] = '0'; |
287 | 0 | } |
288 | 0 | else |
289 | 0 | { |
290 | 0 | char cHexDigit1 = cIntToHexDigit( iValue % 16 ); |
291 | 0 | iValue /= 16; |
292 | 0 | char cHexDigit2 = cIntToHexDigit( iValue ); |
293 | 0 | pchDest[iDestPos++] = cHexDigit2; |
294 | 0 | pchDest[iDestPos++] = cHexDigit1; |
295 | 0 | } |
296 | 0 | } |
297 | 0 | } |
298 | 0 | else |
299 | 0 | { |
300 | 0 | pchDest[iDestPos++] = pchSource[i]; |
301 | 0 | } |
302 | 0 | } |
303 | 0 |
|
304 | 0 | if( (iDestPos+1) > nDestLen ) |
305 | 0 | { |
306 | 0 | pchDest[0] = '\0'; |
307 | 0 | //AssertMsg( false, "Target buffer too short to terminate\n" ); |
308 | 0 | return; |
309 | 0 | } |
310 | 0 | |
311 | 0 | // Null terminate |
312 | 0 | pchDest[iDestPos++] = 0; |
313 | 0 | } |
314 | | |
315 | | |
316 | | //----------------------------------------------------------------------------- |
317 | | // Purpose: Internal implementation of decode, works in the strict RFC manner, or |
318 | | // with spaces turned to + like HTML form encoding. |
319 | | // |
320 | | // Returns the amount of space used in the output buffer. |
321 | | //----------------------------------------------------------------------------- |
322 | | size_t V_URLDecodeInternal( char *pchDecodeDest, int nDecodeDestLen, const char *pchEncodedSource, int nEncodedSourceLen, bool bUsePlusForSpace ) |
323 | 0 | { |
324 | 0 | if ( nDecodeDestLen < nEncodedSourceLen ) |
325 | 0 | { |
326 | 0 | //AssertMsg( false, "V_URLDecode needs a dest buffer at least as large as the source" ); |
327 | 0 | return 0; |
328 | 0 | } |
329 | 0 | |
330 | 0 | int iDestPos = 0; |
331 | 0 | for( int i=0; i < nEncodedSourceLen; ++i ) |
332 | 0 | { |
333 | 0 | if ( bUsePlusForSpace && pchEncodedSource[i] == '+' ) |
334 | 0 | { |
335 | 0 | pchDecodeDest[ iDestPos++ ] = ' '; |
336 | 0 | } |
337 | 0 | else if ( pchEncodedSource[i] == '%' ) |
338 | 0 | { |
339 | 0 | // Percent signifies an encoded value, look ahead for the hex code, convert to numeric, and use that |
340 | 0 |
|
341 | 0 | // First make sure we have 2 more chars |
342 | 0 | if ( i < nEncodedSourceLen - 2 ) |
343 | 0 | { |
344 | 0 | char cHexDigit1 = pchEncodedSource[i+1]; |
345 | 0 | char cHexDigit2 = pchEncodedSource[i+2]; |
346 | 0 |
|
347 | 0 | // Turn the chars into a hex value, if they are not valid, then we'll |
348 | 0 | // just place the % and the following two chars direct into the string, |
349 | 0 | // even though this really shouldn't happen, who knows what bad clients |
350 | 0 | // may do with encoding. |
351 | 0 | bool bValid = false; |
352 | 0 | int iValue = iHexCharToInt( cHexDigit1 ); |
353 | 0 | if ( iValue != -1 ) |
354 | 0 | { |
355 | 0 | iValue *= 16; |
356 | 0 | int iValue2 = iHexCharToInt( cHexDigit2 ); |
357 | 0 | if ( iValue2 != -1 ) |
358 | 0 | { |
359 | 0 | iValue += iValue2; |
360 | 0 | pchDecodeDest[ iDestPos++ ] = (char)iValue; |
361 | 0 | bValid = true; |
362 | 0 | } |
363 | 0 | } |
364 | 0 |
|
365 | 0 | if ( !bValid ) |
366 | 0 | { |
367 | 0 | pchDecodeDest[ iDestPos++ ] = '%'; |
368 | 0 | pchDecodeDest[ iDestPos++ ] = cHexDigit1; |
369 | 0 | pchDecodeDest[ iDestPos++ ] = cHexDigit2; |
370 | 0 | } |
371 | 0 | } |
372 | 0 |
|
373 | 0 | // Skip ahead |
374 | 0 | i += 2; |
375 | 0 | } |
376 | 0 | else |
377 | 0 | { |
378 | 0 | pchDecodeDest[ iDestPos++ ] = pchEncodedSource[i]; |
379 | 0 | } |
380 | 0 | } |
381 | 0 |
|
382 | 0 | // We may not have extra room to NULL terminate, since this can be used on raw data, but if we do |
383 | 0 | // go ahead and do it as this can avoid bugs. |
384 | 0 | if ( iDestPos < nDecodeDestLen ) |
385 | 0 | { |
386 | 0 | pchDecodeDest[iDestPos] = 0; |
387 | 0 | } |
388 | 0 |
|
389 | 0 | return (size_t)iDestPos; |
390 | 0 | } |
391 | | |
392 | | //----------------------------------------------------------------------------- |
393 | | // Purpose: Encodes a string (or binary data) from URL encoding format, see rfc1738 section 2.2. |
394 | | // This version of the call isn't a strict RFC implementation, but uses + for space as is |
395 | | // the standard in HTML form encoding, despite it not being part of the RFC. |
396 | | // |
397 | | // Dest buffer should be at least as large as source buffer to guarantee room for decode. |
398 | | //----------------------------------------------------------------------------- |
399 | | void V_URLEncode( char *pchDest, int nDestLen, const char *pchSource, int nSourceLen ) |
400 | 0 | { |
401 | 0 | return V_URLEncodeInternal( pchDest, nDestLen, pchSource, nSourceLen, true ); |
402 | 0 | } |
403 | | |
404 | | |
405 | | //----------------------------------------------------------------------------- |
406 | | // Purpose: Decodes a string (or binary data) from URL encoding format, see rfc1738 section 2.2. |
407 | | // This version of the call isn't a strict RFC implementation, but uses + for space as is |
408 | | // the standard in HTML form encoding, despite it not being part of the RFC. |
409 | | // |
410 | | // Dest buffer should be at least as large as source buffer to guarantee room for decode. |
411 | | // Dest buffer being the same as the source buffer (decode in-place) is explicitly allowed. |
412 | | //----------------------------------------------------------------------------- |
413 | | size_t V_URLDecode( char *pchDecodeDest, int nDecodeDestLen, const char *pchEncodedSource, int nEncodedSourceLen ) |
414 | 0 | { |
415 | 0 | return V_URLDecodeInternal( pchDecodeDest, nDecodeDestLen, pchEncodedSource, nEncodedSourceLen, true ); |
416 | 0 | } |
417 | | |
418 | | //----------------------------------------------------------------------------- |
419 | | void V_StripExtension( std::string &in ) |
420 | 0 | { |
421 | 0 | // Find the last dot. If it's followed by a dot or a slash, then it's part of a |
422 | 0 | // directory specifier like ../../somedir/./blah. |
423 | 0 | std::string::size_type test = in.rfind( '.' ); |
424 | 0 | if ( test != std::string::npos ) |
425 | 0 | { |
426 | 0 | // This handles things like ".\blah" or "c:\my@email.com\abc\def\geh" |
427 | 0 | // Which would otherwise wind up with "" and "c:\my@email", respectively. |
428 | 0 | if ( in.rfind( '\\' ) < test && in.rfind( '/' ) < test ) |
429 | 0 | { |
430 | 0 | in.resize( test ); |
431 | 0 | } |
432 | 0 | } |
433 | 0 | } |
434 | | |
435 | | |
436 | | //----------------------------------------------------------------------------- |
437 | | // Purpose: Tokenizes a string into a vector of strings |
438 | | //----------------------------------------------------------------------------- |
439 | | std::vector<std::string> TokenizeString( const std::string & sString, char cToken ) |
440 | 0 | { |
441 | 0 | std::vector<std::string> vecStrings; |
442 | 0 | std::istringstream stream( sString ); |
443 | 0 | std::string s; |
444 | 0 | while ( std::getline( stream, s, cToken ) ) |
445 | 0 | { |
446 | 0 | vecStrings.push_back( s ); |
447 | 0 | } |
448 | 0 | return vecStrings; |
449 | 0 | } |
450 | | |