Line data Source code
1 : //========= Copyright Valve Corporation ============//
2 : #include "strtools_public.h"
3 : #include "pathtools_public.h"
4 :
5 : #if defined( _WIN32)
6 : #include <windows.h>
7 : #include <direct.h>
8 : #include <shobjidl.h>
9 : #include <knownfolders.h>
10 : #include <shlobj.h>
11 : #include <share.h>
12 :
13 : #undef GetEnvironmentVariable
14 : #else
15 : #include <dlfcn.h>
16 : #include <stdio.h>
17 : #include <unistd.h>
18 : #include <stdlib.h>
19 : #endif
20 : #if defined OSX
21 : #include <Foundation/Foundation.h>
22 : #include <AppKit/AppKit.h>
23 : #include <mach-o/dyld.h>
24 : #define _S_IFDIR S_IFDIR // really from tier0/platform.h which we dont have yet
25 : #endif
26 :
27 : #include <sys/stat.h>
28 :
29 : #include <algorithm>
30 :
31 : /** Returns the path (including filename) to the current executable */
32 0 : std::string Path_GetExecutablePath()
33 : {
34 : #if defined( _WIN32 )
35 : wchar_t *pwchPath = new wchar_t[MAX_UNICODE_PATH];
36 : char *pchPath = new char[MAX_UNICODE_PATH_IN_UTF8];
37 : ::GetModuleFileNameW( NULL, pwchPath, MAX_UNICODE_PATH );
38 : WideCharToMultiByte( CP_UTF8, 0, pwchPath, -1, pchPath, MAX_UNICODE_PATH_IN_UTF8, NULL, NULL );
39 : delete[] pwchPath;
40 :
41 : std::string sPath = pchPath;
42 : delete[] pchPath;
43 : return sPath;
44 : #elif defined( OSX )
45 : char rchPath[1024];
46 : uint32_t nBuff = sizeof( rchPath );
47 : bool bSuccess = _NSGetExecutablePath(rchPath, &nBuff) == 0;
48 : rchPath[nBuff-1] = '\0';
49 : if( bSuccess )
50 : return rchPath;
51 : else
52 : return "";
53 : #elif defined LINUX
54 : char rchPath[1024];
55 0 : size_t nBuff = sizeof( rchPath );
56 0 : ssize_t nRead = readlink("/proc/self/exe", rchPath, nBuff-1 );
57 0 : if ( nRead != -1 )
58 : {
59 0 : rchPath[ nRead ] = 0;
60 0 : return rchPath;
61 : }
62 : else
63 : {
64 0 : return "";
65 : }
66 : #else
67 : AssertMsg( false, "Implement Plat_GetExecutablePath" );
68 : return "";
69 : #endif
70 :
71 : }
72 :
73 : /** Returns the path of the current working directory */
74 0 : std::string Path_GetWorkingDirectory()
75 : {
76 0 : std::string sPath;
77 : #if defined( _WIN32 )
78 : wchar_t buf[MAX_UNICODE_PATH];
79 : sPath = UTF16to8( _wgetcwd( buf, MAX_UNICODE_PATH ) );
80 : #else
81 : char buf[ 1024 ];
82 0 : sPath = getcwd( buf, sizeof( buf ) );
83 : #endif
84 0 : return sPath;
85 : }
86 :
87 : /** Sets the path of the current working directory. Returns true if this was successful. */
88 0 : bool Path_SetWorkingDirectory( const std::string & sPath )
89 : {
90 : bool bSuccess;
91 : #if defined( _WIN32 )
92 : std::wstring wsPath = UTF8to16( sPath.c_str() );
93 : bSuccess = 0 == _wchdir( wsPath.c_str() );
94 : #else
95 0 : bSuccess = 0 == chdir( sPath.c_str() );
96 : #endif
97 0 : return bSuccess;
98 : }
99 :
100 : /** Returns the specified path without its filename */
101 0 : std::string Path_StripFilename( const std::string & sPath, char slash )
102 : {
103 0 : if( slash == 0 )
104 0 : slash = Path_GetSlash();
105 :
106 0 : std::string::size_type n = sPath.find_last_of( slash );
107 0 : if( n == std::string::npos )
108 0 : return sPath;
109 : else
110 0 : return std::string( sPath.begin(), sPath.begin() + n );
111 : }
112 :
113 : /** returns just the filename from the provided full or relative path. */
114 0 : std::string Path_StripDirectory( const std::string & sPath, char slash )
115 : {
116 0 : if( slash == 0 )
117 0 : slash = Path_GetSlash();
118 :
119 0 : std::string::size_type n = sPath.find_last_of( slash );
120 0 : if( n == std::string::npos )
121 0 : return sPath;
122 : else
123 0 : return std::string( sPath.begin() + n + 1, sPath.end() );
124 : }
125 :
126 : /** returns just the filename with no extension of the provided filename.
127 : * If there is a path the path is left intact. */
128 0 : std::string Path_StripExtension( const std::string & sPath )
129 : {
130 0 : for( std::string::const_reverse_iterator i = sPath.rbegin(); i != sPath.rend(); i++ )
131 : {
132 0 : if( *i == '.' )
133 : {
134 0 : return std::string( sPath.begin(), i.base() - 1 );
135 : }
136 :
137 : // if we find a slash there is no extension
138 0 : if( *i == '\\' || *i == '/' )
139 0 : break;
140 : }
141 :
142 : // we didn't find an extension
143 0 : return sPath;
144 : }
145 :
146 : /** returns just extension of the provided filename (if any). */
147 0 : std::string Path_GetExtension( const std::string & sPath )
148 : {
149 0 : for ( std::string::const_reverse_iterator i = sPath.rbegin(); i != sPath.rend(); i++ )
150 : {
151 0 : if ( *i == '.' )
152 : {
153 0 : return std::string( i.base(), sPath.end() );
154 : }
155 :
156 : // if we find a slash there is no extension
157 0 : if ( *i == '\\' || *i == '/' )
158 0 : break;
159 : }
160 :
161 : // we didn't find an extension
162 0 : return "";
163 : }
164 :
165 0 : bool Path_IsAbsolute( const std::string & sPath )
166 : {
167 0 : if( sPath.empty() )
168 0 : return false;
169 :
170 : #if defined( WIN32 )
171 : if ( sPath.size() < 3 ) // must be c:\x or \\x at least
172 : return false;
173 :
174 : if ( sPath[1] == ':' ) // drive letter plus slash, but must test both slash cases
175 : {
176 : if ( sPath[2] == '\\' || sPath[2] == '/' )
177 : return true;
178 : }
179 : else if ( sPath[0] == '\\' && sPath[1] == '\\' ) // UNC path
180 : return true;
181 : #else
182 0 : if( sPath[0] == '\\' || sPath[0] == '/' ) // any leading slash
183 0 : return true;
184 : #endif
185 :
186 0 : return false;
187 : }
188 :
189 :
190 : /** Makes an absolute path from a relative path and a base path */
191 0 : std::string Path_MakeAbsolute( const std::string & sRelativePath, const std::string & sBasePath, char slash )
192 : {
193 0 : if( slash == 0 )
194 0 : slash = Path_GetSlash();
195 :
196 0 : if( Path_IsAbsolute( sRelativePath ) )
197 0 : return sRelativePath;
198 : else
199 : {
200 0 : if( !Path_IsAbsolute( sBasePath ) )
201 0 : return "";
202 :
203 0 : std::string sCompacted = Path_Compact( Path_Join( sBasePath, sRelativePath, slash ), slash );
204 0 : if( Path_IsAbsolute( sCompacted ) )
205 0 : return sCompacted;
206 : else
207 0 : return "";
208 : }
209 : }
210 :
211 :
212 : /** Fixes the directory separators for the current platform */
213 0 : std::string Path_FixSlashes( const std::string & sPath, char slash )
214 : {
215 0 : if( slash == 0 )
216 0 : slash = Path_GetSlash();
217 :
218 0 : std::string sFixed = sPath;
219 0 : for( std::string::iterator i = sFixed.begin(); i != sFixed.end(); i++ )
220 : {
221 0 : if( *i == '/' || *i == '\\' )
222 0 : *i = slash;
223 : }
224 :
225 0 : return sFixed;
226 : }
227 :
228 :
229 0 : char Path_GetSlash()
230 : {
231 : #if defined(_WIN32)
232 : return '\\';
233 : #else
234 0 : return '/';
235 : #endif
236 : }
237 :
238 : /** Jams two paths together with the right kind of slash */
239 0 : std::string Path_Join( const std::string & first, const std::string & second, char slash )
240 : {
241 0 : if( slash == 0 )
242 0 : slash = Path_GetSlash();
243 :
244 : // only insert a slash if we don't already have one
245 0 : std::string::size_type nLen = first.length();
246 0 : if( !nLen )
247 0 : return second;
248 : #if defined(_WIN32)
249 : if( first.back() == '\\' || first.back() == '/' )
250 : nLen--;
251 : #else
252 0 : char last_char = first[first.length()-1];
253 0 : if (last_char == '\\' || last_char == '/')
254 0 : nLen--;
255 : #endif
256 :
257 0 : return first.substr( 0, nLen ) + std::string( 1, slash ) + second;
258 : }
259 :
260 :
261 0 : std::string Path_Join( const std::string & first, const std::string & second, const std::string & third, char slash )
262 : {
263 0 : return Path_Join( Path_Join( first, second, slash ), third, slash );
264 : }
265 :
266 0 : std::string Path_Join( const std::string & first, const std::string & second, const std::string & third, const std::string &fourth, char slash )
267 : {
268 0 : return Path_Join( Path_Join( Path_Join( first, second, slash ), third, slash ), fourth, slash );
269 : }
270 :
271 0 : std::string Path_Join(
272 : const std::string & first,
273 : const std::string & second,
274 : const std::string & third,
275 : const std::string & fourth,
276 : const std::string & fifth,
277 : char slash )
278 : {
279 0 : return Path_Join( Path_Join( Path_Join( Path_Join( first, second, slash ), third, slash ), fourth, slash ), fifth, slash );
280 : }
281 :
282 :
283 0 : std::string Path_RemoveTrailingSlash( const std::string & sRawPath, char slash )
284 : {
285 0 : if ( slash == 0 )
286 0 : slash = Path_GetSlash();
287 :
288 0 : std::string sPath = sRawPath;
289 0 : std::string::size_type nCurrent = sRawPath.length();
290 0 : if ( nCurrent == 0 )
291 0 : return sPath;
292 :
293 0 : int nLastFound = -1;
294 0 : nCurrent--;
295 0 : while( nCurrent != 0 )
296 : {
297 0 : if ( sRawPath[ nCurrent ] == slash )
298 : {
299 0 : nLastFound = (int)nCurrent;
300 0 : nCurrent--;
301 : }
302 : else
303 : {
304 0 : break;
305 : }
306 : }
307 :
308 0 : if ( nLastFound >= 0 )
309 : {
310 0 : sPath.erase( nLastFound, std::string::npos );
311 : }
312 :
313 0 : return sPath;
314 : }
315 :
316 :
317 : /** Removes redundant <dir>/.. elements in the path. Returns an empty path if the
318 : * specified path has a broken number of directories for its number of ..s */
319 0 : std::string Path_Compact( const std::string & sRawPath, char slash )
320 : {
321 0 : if( slash == 0 )
322 0 : slash = Path_GetSlash();
323 :
324 0 : std::string sPath = Path_FixSlashes( sRawPath, slash );
325 0 : std::string sSlashString( 1, slash );
326 :
327 : // strip out all /./
328 0 : for( std::string::size_type i = 0; (i + 3) < sPath.length(); )
329 : {
330 0 : if( sPath[ i ] == slash && sPath[ i+1 ] == '.' && sPath[ i+2 ] == slash )
331 : {
332 0 : sPath.replace( i, 3, sSlashString );
333 : }
334 : else
335 : {
336 0 : ++i;
337 : }
338 : }
339 :
340 :
341 : // get rid of trailing /. but leave the path separator
342 0 : if( sPath.length() > 2 )
343 : {
344 0 : std::string::size_type len = sPath.length();
345 0 : if( sPath[ len-1 ] == '.' && sPath[ len-2 ] == slash )
346 : {
347 : // sPath.pop_back();
348 0 : sPath[len-1] = 0; // for now, at least
349 : }
350 : }
351 :
352 : // get rid of leading ./
353 0 : if( sPath.length() > 2 )
354 : {
355 0 : if( sPath[ 0 ] == '.' && sPath[ 1 ] == slash )
356 : {
357 0 : sPath.replace( 0, 2, "" );
358 : }
359 : }
360 :
361 : // each time we encounter .. back up until we've found the previous directory name
362 : // then get rid of both
363 0 : std::string::size_type i = 0;
364 0 : while( i < sPath.length() )
365 : {
366 0 : if( i > 0 && sPath.length() - i >= 2
367 0 : && sPath[i] == '.'
368 0 : && sPath[i+1] == '.'
369 0 : && ( i + 2 == sPath.length() || sPath[ i+2 ] == slash )
370 0 : && sPath[ i-1 ] == slash )
371 : {
372 : // check if we've hit the start of the string and have a bogus path
373 0 : if( i == 1 )
374 0 : return "";
375 :
376 : // find the separator before i-1
377 0 : std::string::size_type iDirStart = i-2;
378 0 : while( iDirStart > 0 && sPath[ iDirStart - 1 ] != slash )
379 0 : --iDirStart;
380 :
381 : // remove everything from iDirStart to i+2
382 0 : sPath.replace( iDirStart, (i - iDirStart) + 3, "" );
383 :
384 : // start over
385 0 : i = 0;
386 : }
387 : else
388 : {
389 0 : ++i;
390 : }
391 : }
392 :
393 0 : return sPath;
394 : }
395 :
396 :
397 : /** Returns the path to the current DLL or exe */
398 0 : std::string Path_GetThisModulePath()
399 : {
400 : // gets the path of vrclient.dll itself
401 : #ifdef WIN32
402 : HMODULE hmodule = NULL;
403 :
404 : ::GetModuleHandleEx( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, reinterpret_cast<LPCTSTR>(Path_GetThisModulePath), &hmodule );
405 :
406 : wchar_t *pwchPath = new wchar_t[MAX_UNICODE_PATH];
407 : char *pchPath = new char[ MAX_UNICODE_PATH_IN_UTF8 ];
408 : ::GetModuleFileNameW( hmodule, pwchPath, MAX_UNICODE_PATH );
409 : WideCharToMultiByte( CP_UTF8, 0, pwchPath, -1, pchPath, MAX_UNICODE_PATH_IN_UTF8, NULL, NULL );
410 : delete[] pwchPath;
411 :
412 : std::string sPath = pchPath;
413 : delete [] pchPath;
414 : return sPath;
415 :
416 : #elif defined( OSX ) || defined( LINUX )
417 : // get the addr of a function in vrclient.so and then ask the dlopen system about it
418 : Dl_info info;
419 0 : dladdr( (void *)Path_GetThisModulePath, &info );
420 0 : return info.dli_fname;
421 : #endif
422 :
423 : }
424 :
425 :
426 : /** returns true if the specified path exists and is a directory */
427 0 : bool Path_IsDirectory( const std::string & sPath )
428 : {
429 0 : std::string sFixedPath = Path_FixSlashes( sPath );
430 0 : if( sFixedPath.empty() )
431 0 : return false;
432 0 : char cLast = sFixedPath[ sFixedPath.length() - 1 ];
433 0 : if( cLast == '/' || cLast == '\\' )
434 0 : sFixedPath.erase( sFixedPath.end() - 1, sFixedPath.end() );
435 :
436 : // see if the specified path actually exists.
437 :
438 : #if defined(POSIX)
439 : struct stat buf;
440 0 : if ( stat( sFixedPath.c_str(), &buf ) == -1 )
441 : {
442 0 : return false;
443 : }
444 :
445 : #if defined( LINUX ) || defined( OSX )
446 0 : return S_ISDIR( buf.st_mode );
447 : #else
448 : return (buf.st_mode & _S_IFDIR) != 0;
449 : #endif
450 :
451 : #else
452 : struct _stat buf;
453 : std::wstring wsFixedPath = UTF8to16( sFixedPath.c_str() );
454 : if ( _wstat( wsFixedPath.c_str(), &buf ) == -1 )
455 : {
456 : return false;
457 : }
458 :
459 : return (buf.st_mode & _S_IFDIR) != 0;
460 : #endif
461 : }
462 :
463 : /** returns true if the specified path represents an app bundle */
464 0 : bool Path_IsAppBundle( const std::string & sPath )
465 : {
466 : #if defined(OSX)
467 : NSBundle *bundle = [ NSBundle bundleWithPath: [ NSString stringWithUTF8String:sPath.c_str() ] ];
468 : bool bisAppBundle = ( nullptr != bundle );
469 : [ bundle release ];
470 : return bisAppBundle;
471 : #else
472 0 : return false;
473 : #endif
474 : }
475 :
476 : //-----------------------------------------------------------------------------
477 : // Purpose: returns true if the the path exists
478 : //-----------------------------------------------------------------------------
479 0 : bool Path_Exists( const std::string & sPath )
480 : {
481 0 : std::string sFixedPath = Path_FixSlashes( sPath );
482 0 : if( sFixedPath.empty() )
483 0 : return false;
484 :
485 : #if defined( WIN32 )
486 : struct _stat buf;
487 : std::wstring wsFixedPath = UTF8to16( sFixedPath.c_str() );
488 : if ( _wstat( wsFixedPath.c_str(), &buf ) == -1 )
489 : {
490 : return false;
491 : }
492 : #else
493 : struct stat buf;
494 0 : if ( stat ( sFixedPath.c_str(), &buf ) == -1)
495 : {
496 0 : return false;
497 : }
498 : #endif
499 :
500 0 : return true;
501 : }
502 :
503 :
504 : //-----------------------------------------------------------------------------
505 : // Purpose: helper to find a directory upstream from a given path
506 : //-----------------------------------------------------------------------------
507 0 : std::string Path_FindParentDirectoryRecursively( const std::string &strStartDirectory, const std::string &strDirectoryName )
508 : {
509 0 : std::string strFoundPath = "";
510 0 : std::string strCurrentPath = Path_FixSlashes( strStartDirectory );
511 0 : if ( strCurrentPath.length() == 0 )
512 0 : return "";
513 :
514 0 : bool bExists = Path_Exists( strCurrentPath );
515 0 : std::string strCurrentDirectoryName = Path_StripDirectory( strCurrentPath );
516 0 : if ( bExists && stricmp( strCurrentDirectoryName.c_str(), strDirectoryName.c_str() ) == 0 )
517 0 : return strCurrentPath;
518 :
519 0 : while( bExists && strCurrentPath.length() != 0 )
520 : {
521 0 : strCurrentPath = Path_StripFilename( strCurrentPath );
522 0 : strCurrentDirectoryName = Path_StripDirectory( strCurrentPath );
523 0 : bExists = Path_Exists( strCurrentPath );
524 0 : if ( bExists && stricmp( strCurrentDirectoryName.c_str(), strDirectoryName.c_str() ) == 0 )
525 0 : return strCurrentPath;
526 : }
527 :
528 0 : return "";
529 : }
530 :
531 :
532 : //-----------------------------------------------------------------------------
533 : // Purpose: helper to find a subdirectory upstream from a given path
534 : //-----------------------------------------------------------------------------
535 0 : std::string Path_FindParentSubDirectoryRecursively( const std::string &strStartDirectory, const std::string &strDirectoryName )
536 : {
537 0 : std::string strFoundPath = "";
538 0 : std::string strCurrentPath = Path_FixSlashes( strStartDirectory );
539 0 : if ( strCurrentPath.length() == 0 )
540 0 : return "";
541 :
542 0 : bool bExists = Path_Exists( strCurrentPath );
543 0 : while( bExists && strCurrentPath.length() != 0 )
544 : {
545 0 : strCurrentPath = Path_StripFilename( strCurrentPath );
546 0 : bExists = Path_Exists( strCurrentPath );
547 :
548 0 : if( Path_Exists( Path_Join( strCurrentPath, strDirectoryName ) ) )
549 : {
550 0 : strFoundPath = Path_Join( strCurrentPath, strDirectoryName );
551 0 : break;
552 : }
553 : }
554 0 : return strFoundPath;
555 : }
556 :
557 :
558 : //-----------------------------------------------------------------------------
559 : // Purpose: reading and writing files in the vortex directory
560 : //-----------------------------------------------------------------------------
561 0 : unsigned char * Path_ReadBinaryFile( const std::string &strFilename, int *pSize )
562 : {
563 : FILE *f;
564 : #if defined( POSIX )
565 0 : f = fopen( strFilename.c_str(), "rb" );
566 : #else
567 : std::wstring wstrFilename = UTF8to16( strFilename.c_str() );
568 : // the open operation needs to be sharable, therefore use of _wfsopen instead of _wfopen_s
569 : f = _wfsopen( wstrFilename.c_str(), L"rb", _SH_DENYNO );
570 : #endif
571 :
572 0 : unsigned char* buf = NULL;
573 :
574 0 : if ( f != NULL )
575 : {
576 0 : fseek(f, 0, SEEK_END);
577 0 : int size = ftell(f);
578 0 : fseek(f, 0, SEEK_SET);
579 :
580 0 : buf = new unsigned char[size];
581 0 : if (buf && fread(buf, size, 1, f) == 1)
582 : {
583 0 : if (pSize)
584 0 : *pSize = size;
585 : }
586 : else
587 : {
588 0 : delete[] buf;
589 0 : buf = 0;
590 : }
591 :
592 0 : fclose(f);
593 : }
594 :
595 0 : return buf;
596 : }
597 :
598 0 : uint32_t Path_ReadBinaryFile( const std::string &strFilename, unsigned char *pBuffer, uint32_t unSize )
599 : {
600 : FILE *f;
601 : #if defined( POSIX )
602 0 : f = fopen( strFilename.c_str(), "rb" );
603 : #else
604 : std::wstring wstrFilename = UTF8to16( strFilename.c_str() );
605 : errno_t err = _wfopen_s( &f, wstrFilename.c_str(), L"rb" );
606 : if ( err != 0 )
607 : {
608 : f = NULL;
609 : }
610 : #endif
611 :
612 0 : uint32_t unSizeToReturn = 0;
613 :
614 0 : if ( f != NULL )
615 : {
616 0 : fseek( f, 0, SEEK_END );
617 0 : uint32_t size = (uint32_t)ftell( f );
618 0 : fseek( f, 0, SEEK_SET );
619 :
620 0 : if ( size > unSize || !pBuffer )
621 : {
622 0 : unSizeToReturn = (uint32_t)size;
623 : }
624 : else
625 : {
626 0 : if ( fread( pBuffer, size, 1, f ) == 1 )
627 : {
628 0 : unSizeToReturn = (uint32_t)size;
629 : }
630 : }
631 :
632 0 : fclose( f );
633 : }
634 :
635 0 : return unSizeToReturn;
636 : }
637 :
638 0 : bool Path_WriteBinaryFile(const std::string &strFilename, unsigned char *pData, unsigned nSize)
639 : {
640 : FILE *f;
641 : #if defined( POSIX )
642 0 : f = fopen(strFilename.c_str(), "wb");
643 : #else
644 : std::wstring wstrFilename = UTF8to16( strFilename.c_str() );
645 : errno_t err = _wfopen_s( &f, wstrFilename.c_str(), L"wb" );
646 : if (err != 0)
647 : {
648 : f = NULL;
649 : }
650 : #endif
651 :
652 0 : size_t written = 0;
653 0 : if (f != NULL) {
654 0 : written = fwrite(pData, sizeof(unsigned char), nSize, f);
655 0 : fclose(f);
656 : }
657 :
658 0 : return written = nSize ? true : false;
659 : }
660 :
661 0 : std::string Path_ReadTextFile( const std::string &strFilename )
662 : {
663 : // doing it this way seems backwards, but I don't
664 : // see an easy way to do this with C/C++ style IO
665 : // that isn't worse...
666 : int size;
667 0 : unsigned char* buf = Path_ReadBinaryFile( strFilename, &size );
668 0 : if (!buf)
669 0 : return "";
670 :
671 : // convert CRLF -> LF
672 0 : size_t outsize = 1;
673 0 : for (int i=1; i < size; i++)
674 : {
675 0 : if (buf[i] == '\n' && buf[i-1] == '\r') // CRLF
676 0 : buf[outsize-1] = '\n'; // ->LF
677 : else
678 0 : buf[outsize++] = buf[i]; // just copy
679 : }
680 :
681 0 : std::string ret((char *)buf, outsize);
682 0 : delete[] buf;
683 0 : return ret;
684 : }
685 :
686 :
687 0 : bool Path_WriteStringToTextFile( const std::string &strFilename, const char *pchData )
688 : {
689 : FILE *f;
690 : #if defined( POSIX )
691 0 : f = fopen( strFilename.c_str(), "w" );
692 : #else
693 : std::wstring wstrFilename = UTF8to16( strFilename.c_str() );
694 : errno_t err = _wfopen_s( &f, wstrFilename.c_str(), L"w" );
695 : if ( err != 0 )
696 : {
697 : f = NULL;
698 : }
699 : #endif
700 :
701 0 : bool ok = false;
702 :
703 0 : if ( f != NULL )
704 : {
705 0 : ok = fputs( pchData, f) >= 0;
706 0 : fclose(f);
707 : }
708 :
709 0 : return ok;
710 : }
711 :
712 0 : bool Path_WriteStringToTextFileAtomic( const std::string &strFilename, const char *pchData )
713 : {
714 0 : std::string strTmpFilename = strFilename + ".tmp";
715 :
716 0 : if ( !Path_WriteStringToTextFile( strTmpFilename, pchData ) )
717 0 : return false;
718 :
719 : // Platform specific atomic file replacement
720 : #if defined( _WIN32 )
721 : std::wstring wsFilename = UTF8to16( strFilename.c_str() );
722 : std::wstring wsTmpFilename = UTF8to16( strTmpFilename.c_str() );
723 : if ( !::ReplaceFileW( wsFilename.c_str(), wsTmpFilename.c_str(), nullptr, 0, 0, 0 ) )
724 : {
725 : // if we couldn't ReplaceFile, try a non-atomic write as a fallback
726 : if ( !Path_WriteStringToTextFile( strFilename, pchData ) )
727 : return false;
728 : }
729 : #elif defined( POSIX )
730 0 : if ( rename( strTmpFilename.c_str(), strFilename.c_str() ) == -1 )
731 0 : return false;
732 : #else
733 : #error Do not know how to write atomic file
734 : #endif
735 :
736 0 : return true;
737 : }
738 :
739 :
740 : #if defined(WIN32)
741 : #define FILE_URL_PREFIX "file:///"
742 : #else
743 : #define FILE_URL_PREFIX "file://"
744 : #endif
745 :
746 : // ----------------------------------------------------------------------------------------------------------------------------
747 : // Purpose: Turns a path to a file on disk into a URL (or just returns the value if it's already a URL)
748 : // ----------------------------------------------------------------------------------------------------------------------------
749 0 : std::string Path_FilePathToUrl( const std::string & sRelativePath, const std::string & sBasePath )
750 : {
751 0 : if ( !strnicmp( sRelativePath.c_str(), "http://", 7 )
752 0 : || !strnicmp( sRelativePath.c_str(), "https://", 8 )
753 0 : || !strnicmp( sRelativePath.c_str(), "file://", 7 ) )
754 : {
755 0 : return sRelativePath;
756 : }
757 : else
758 : {
759 0 : std::string sAbsolute = Path_MakeAbsolute( sRelativePath, sBasePath );
760 0 : if ( sAbsolute.empty() )
761 0 : return sAbsolute;
762 0 : return std::string( FILE_URL_PREFIX ) + sAbsolute;
763 : }
764 : }
765 :
766 : // -----------------------------------------------------------------------------------------------------
767 : // Purpose: Strips off file:// off a URL and returns the path. For other kinds of URLs an empty string is returned
768 : // -----------------------------------------------------------------------------------------------------
769 0 : std::string Path_UrlToFilePath( const std::string & sFileUrl )
770 : {
771 0 : if ( !strnicmp( sFileUrl.c_str(), FILE_URL_PREFIX, strlen( FILE_URL_PREFIX ) ) )
772 : {
773 0 : return sFileUrl.c_str() + strlen( FILE_URL_PREFIX );
774 : }
775 : else
776 : {
777 0 : return "";
778 : }
779 : }
780 :
781 :
782 : // -----------------------------------------------------------------------------------------------------
783 : // Purpose: Returns the root of the directory the system wants us to store user documents in
784 : // -----------------------------------------------------------------------------------------------------
785 0 : std::string GetUserDocumentsPath()
786 : {
787 : #if defined( WIN32 )
788 : WCHAR rwchPath[MAX_PATH];
789 :
790 : if ( !SUCCEEDED( SHGetFolderPathW( NULL, CSIDL_MYDOCUMENTS | CSIDL_FLAG_CREATE, NULL, 0, rwchPath ) ) )
791 : {
792 : return "";
793 : }
794 :
795 : // Convert the path to UTF-8 and store in the output
796 : std::string sUserPath = UTF16to8( rwchPath );
797 :
798 : return sUserPath;
799 : #elif defined( OSX )
800 : @autoreleasepool {
801 : NSArray *paths = NSSearchPathForDirectoriesInDomains( NSDocumentDirectory, NSUserDomainMask, YES );
802 : if ( [paths count] == 0 )
803 : {
804 : return "";
805 : }
806 :
807 : return [[paths objectAtIndex:0] UTF8String];
808 : }
809 : #elif defined( LINUX )
810 : // @todo: not solved/changed as part of OSX - still not real - just removed old class based steam cut and paste
811 0 : const char *pchHome = getenv( "HOME" );
812 0 : if ( pchHome == NULL )
813 : {
814 0 : return "";
815 : }
816 0 : return pchHome;
817 : #endif
818 : }
819 :
|