]> git.saurik.com Git - wxWidgets.git/blame - src/common/filename.cpp
extend wxXLocale with wxStrto[d,l,ul] functions; make wxXLocale::Init() a little...
[wxWidgets.git] / src / common / filename.cpp
CommitLineData
df5ddbca 1/////////////////////////////////////////////////////////////////////////////
097ead30
VZ
2// Name: src/common/filename.cpp
3// Purpose: wxFileName - encapsulates a file path
844f90fb 4// Author: Robert Roebling, Vadim Zeitlin
df5ddbca
RR
5// Modified by:
6// Created: 28.12.2000
7// RCS-ID: $Id$
8// Copyright: (c) 2000 Robert Roebling
65571936 9// Licence: wxWindows licence
df5ddbca
RR
10/////////////////////////////////////////////////////////////////////////////
11
04c943b1
VZ
12/*
13 Here are brief descriptions of the filename formats supported by this class:
14
2bc60417
RR
15 wxPATH_UNIX: standard Unix format, used under Darwin as well, absolute file
16 names have the form:
04c943b1
VZ
17 /dir1/dir2/.../dirN/filename, "." and ".." stand for the
18 current and parent directory respectively, "~" is parsed as the
19 user HOME and "~username" as the HOME of that user
20
2bc60417 21 wxPATH_DOS: DOS/Windows format, absolute file names have the form:
04c943b1
VZ
22 drive:\dir1\dir2\...\dirN\filename.ext where drive is a single
23 letter. "." and ".." as for Unix but no "~".
24
25 There are also UNC names of the form \\share\fullpath
26
ae4d7004 27 wxPATH_MAC: Mac OS 8/9 and Mac OS X under CodeWarrior 7 format, absolute file
2bc60417 28 names have the form
04c943b1
VZ
29 volume:dir1:...:dirN:filename
30 and the relative file names are either
31 :dir1:...:dirN:filename
32 or just
33 filename
34 (although :filename works as well).
a385b5df 35 Since the volume is just part of the file path, it is not
353f41cb 36 treated like a separate entity as it is done under DOS and
90a68369 37 VMS, it is just treated as another dir.
04c943b1
VZ
38
39 wxPATH_VMS: VMS native format, absolute file names have the form
40 <device>:[dir1.dir2.dir3]file.txt
41 or
42 <device>:[000000.dir1.dir2.dir3]file.txt
43
44 the <device> is the physical device (i.e. disk). 000000 is the
45 root directory on the device which can be omitted.
46
47 Note that VMS uses different separators unlike Unix:
48 : always after the device. If the path does not contain : than
49 the default (the device of the current directory) is assumed.
ba623ba2 50 [ start of directory specification
04c943b1
VZ
51 . separator between directory and subdirectory
52 ] between directory and file
53 */
54
097ead30
VZ
55// ============================================================================
56// declarations
57// ============================================================================
58
59// ----------------------------------------------------------------------------
60// headers
61// ----------------------------------------------------------------------------
62
df5ddbca
RR
63// For compilers that support precompilation, includes "wx.h".
64#include "wx/wxprec.h"
65
66#ifdef __BORLANDC__
0b9ab0bd 67#pragma hdrstop
df5ddbca
RR
68#endif
69
70#ifndef WX_PRECOMP
57bd4c60
WS
71 #ifdef __WXMSW__
72 #include "wx/msw/wrapwin.h" // For GetShort/LongPathName
73 #endif
ad9835c9
WS
74 #include "wx/dynarray.h"
75 #include "wx/intl.h"
76 #include "wx/log.h"
de6185e2 77 #include "wx/utils.h"
0bf751e7 78 #include "wx/crt.h"
df5ddbca
RR
79#endif
80
81#include "wx/filename.h"
b70a2866 82#include "wx/private/filename.h"
df5ddbca 83#include "wx/tokenzr.h"
844f90fb 84#include "wx/config.h" // for wxExpandEnvVars
35a6691a 85#include "wx/dynlib.h"
110c5094 86#include "wx/dir.h"
df5ddbca 87
57bd4c60
WS
88#if defined(__WIN32__) && defined(__MINGW32__)
89 #include "wx/msw/gccpriv.h"
951cd180
VZ
90#endif
91
1c193821
JS
92#ifdef __WXWINCE__
93#include "wx/msw/private.h"
94#endif
95
76a5e5d2 96#if defined(__WXMAC__)
c933e267 97 #include "wx/osx/private.h" // includes mac headers
76a5e5d2
SC
98#endif
99
951cd180
VZ
100// utime() is POSIX so should normally be available on all Unices
101#ifdef __UNIX_LIKE__
0b9ab0bd
RL
102#include <sys/types.h>
103#include <utime.h>
104#include <sys/stat.h>
105#include <unistd.h>
9e9b65c1
JS
106#endif
107
444d61ba
VS
108#ifdef __DJGPP__
109#include <unistd.h>
110#endif
111
01d981ec 112#ifdef __MWERKS__
31907d03
SC
113#ifdef __MACH__
114#include <sys/types.h>
115#include <utime.h>
116#include <sys/stat.h>
117#include <unistd.h>
118#else
0b9ab0bd
RL
119#include <stat.h>
120#include <unistd.h>
121#include <unix.h>
01d981ec 122#endif
31907d03 123#endif
01d981ec 124
d9f54bb0 125#ifdef __WATCOMC__
0b9ab0bd
RL
126#include <io.h>
127#include <sys/utime.h>
128#include <sys/stat.h>
d9f54bb0
VS
129#endif
130
24eb81cb
DW
131#ifdef __VISAGECPP__
132#ifndef MAX_PATH
133#define MAX_PATH 256
134#endif
135#endif
136
01c9a906 137#ifdef __EMX__
5d66debf 138#include <os2.h>
01c9a906
SN
139#define MAX_PATH _MAX_PATH
140#endif
141
23b8a262 142
bd08f2f7 143#if wxUSE_LONGLONG
060668a1 144extern const wxULongLong wxInvalidSize = (unsigned)-1;
bd08f2f7 145#endif // wxUSE_LONGLONG
23b8a262
JS
146
147
951cd180
VZ
148// ----------------------------------------------------------------------------
149// private classes
150// ----------------------------------------------------------------------------
151
152// small helper class which opens and closes the file - we use it just to get
153// a file handle for the given file name to pass it to some Win32 API function
c67d6888 154#if defined(__WIN32__) && !defined(__WXMICROWIN__)
951cd180
VZ
155
156class wxFileHandle
157{
158public:
6dbb903b
VZ
159 enum OpenMode
160 {
161 Read,
162 Write
163 };
164
6bc176b4 165 wxFileHandle(const wxString& filename, OpenMode mode, int flags = 0)
951cd180
VZ
166 {
167 m_hFile = ::CreateFile
168 (
e0a050e3 169 filename.fn_str(), // name
0ea621cc 170 mode == Read ? GENERIC_READ // access mask
6dbb903b 171 : GENERIC_WRITE,
54bcff35
VZ
172 FILE_SHARE_READ | // sharing mode
173 FILE_SHARE_WRITE, // (allow everything)
6dbb903b
VZ
174 NULL, // no secutity attr
175 OPEN_EXISTING, // creation disposition
6bc176b4 176 flags, // flags
6dbb903b 177 NULL // no template file
951cd180
VZ
178 );
179
180 if ( m_hFile == INVALID_HANDLE_VALUE )
181 {
49a70977
VS
182 if ( mode == Read )
183 wxLogSysError(_("Failed to open '%s' for reading"),
184 filename.c_str());
185 else
186 wxLogSysError(_("Failed to open '%s' for writing"),
187 filename.c_str());
951cd180
VZ
188 }
189 }
190
191 ~wxFileHandle()
192 {
193 if ( m_hFile != INVALID_HANDLE_VALUE )
194 {
195 if ( !::CloseHandle(m_hFile) )
196 {
197 wxLogSysError(_("Failed to close file handle"));
198 }
199 }
200 }
201
f363e05c 202 // return true only if the file could be opened successfully
951cd180
VZ
203 bool IsOk() const { return m_hFile != INVALID_HANDLE_VALUE; }
204
205 // get the handle
206 operator HANDLE() const { return m_hFile; }
207
208private:
209 HANDLE m_hFile;
210};
211
212#endif // __WIN32__
213
214// ----------------------------------------------------------------------------
215// private functions
216// ----------------------------------------------------------------------------
217
e2b87f38 218#if wxUSE_DATETIME && defined(__WIN32__) && !defined(__WXMICROWIN__)
951cd180
VZ
219
220// convert between wxDateTime and FILETIME which is a 64-bit value representing
221// the number of 100-nanosecond intervals since January 1, 1601.
222
d56e2b97 223static void ConvertFileTimeToWx(wxDateTime *dt, const FILETIME &ft)
951cd180 224{
752f10a8 225 FILETIME ftcopy = ft;
6dbb903b 226 FILETIME ftLocal;
752f10a8 227 if ( !::FileTimeToLocalFileTime(&ftcopy, &ftLocal) )
6dbb903b
VZ
228 {
229 wxLogLastError(_T("FileTimeToLocalFileTime"));
230 }
d56e2b97 231
6dbb903b
VZ
232 SYSTEMTIME st;
233 if ( !::FileTimeToSystemTime(&ftLocal, &st) )
234 {
235 wxLogLastError(_T("FileTimeToSystemTime"));
236 }
d56e2b97 237
6dbb903b
VZ
238 dt->Set(st.wDay, wxDateTime::Month(st.wMonth - 1), st.wYear,
239 st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
951cd180
VZ
240}
241
d56e2b97 242static void ConvertWxToFileTime(FILETIME *ft, const wxDateTime& dt)
951cd180 243{
6dbb903b
VZ
244 SYSTEMTIME st;
245 st.wDay = dt.GetDay();
ad816476
WS
246 st.wMonth = (WORD)(dt.GetMonth() + 1);
247 st.wYear = (WORD)dt.GetYear();
6dbb903b
VZ
248 st.wHour = dt.GetHour();
249 st.wMinute = dt.GetMinute();
250 st.wSecond = dt.GetSecond();
251 st.wMilliseconds = dt.GetMillisecond();
252
253 FILETIME ftLocal;
254 if ( !::SystemTimeToFileTime(&st, &ftLocal) )
255 {
256 wxLogLastError(_T("SystemTimeToFileTime"));
257 }
d56e2b97 258
6dbb903b
VZ
259 if ( !::LocalFileTimeToFileTime(&ftLocal, ft) )
260 {
261 wxLogLastError(_T("LocalFileTimeToFileTime"));
262 }
951cd180
VZ
263}
264
e2b87f38 265#endif // wxUSE_DATETIME && __WIN32__
951cd180 266
67c34f64
VZ
267// return a string with the volume par
268static wxString wxGetVolumeString(const wxString& volume, wxPathFormat format)
269{
270 wxString path;
271
272 if ( !volume.empty() )
273 {
6ce27aa2
VZ
274 format = wxFileName::GetFormat(format);
275
67c34f64
VZ
276 // Special Windows UNC paths hack, part 2: undo what we did in
277 // SplitPath() and make an UNC path if we have a drive which is not a
278 // single letter (hopefully the network shares can't be one letter only
279 // although I didn't find any authoritative docs on this)
280 if ( format == wxPATH_DOS && volume.length() > 1 )
281 {
282 path << wxFILE_SEP_PATH_DOS << wxFILE_SEP_PATH_DOS << volume;
283 }
284 else if ( format == wxPATH_DOS || format == wxPATH_VMS )
285 {
286 path << volume << wxFileName::GetVolumeSeparator(format);
287 }
288 // else ignore
289 }
290
291 return path;
292}
293
9e1c7236
VZ
294// return true if the format used is the DOS/Windows one and the string looks
295// like a UNC path
296static bool IsUNCPath(const wxString& path, wxPathFormat format)
297{
298 return format == wxPATH_DOS &&
299 path.length() >= 4 && // "\\a" can't be a UNC path
300 path[0u] == wxFILE_SEP_PATH_DOS &&
301 path[1u] == wxFILE_SEP_PATH_DOS &&
302 path[2u] != wxFILE_SEP_PATH_DOS;
303}
304
097ead30
VZ
305// ============================================================================
306// implementation
307// ============================================================================
308
309// ----------------------------------------------------------------------------
844f90fb 310// wxFileName construction
097ead30 311// ----------------------------------------------------------------------------
df5ddbca 312
a35b27b1
RR
313void wxFileName::Assign( const wxFileName &filepath )
314{
04c943b1 315 m_volume = filepath.GetVolume();
844f90fb 316 m_dirs = filepath.GetDirs();
04c943b1
VZ
317 m_name = filepath.GetName();
318 m_ext = filepath.GetExt();
a2fa5040 319 m_relative = filepath.m_relative;
dfecbee5 320 m_hasExt = filepath.m_hasExt;
df5ddbca
RR
321}
322
04c943b1
VZ
323void wxFileName::Assign(const wxString& volume,
324 const wxString& path,
325 const wxString& name,
326 const wxString& ext,
dfecbee5 327 bool hasExt,
9e1c7236 328 wxPathFormat format)
a7b51bc8 329{
9e1c7236
VZ
330 // we should ignore paths which look like UNC shares because we already
331 // have the volume here and the UNC notation (\\server\path) is only valid
332 // for paths which don't start with a volume, so prevent SetPath() from
333 // recognizing "\\foo\bar" in "c:\\foo\bar" as an UNC path
334 //
335 // note also that this is a rather ugly way to do what we want (passing
336 // some kind of flag telling to ignore UNC paths to SetPath() would be
337 // better) but this is the safest thing to do to avoid breaking backwards
338 // compatibility in 2.8
339 if ( IsUNCPath(path, format) )
340 {
341 // remove one of the 2 leading backslashes to ensure that it's not
342 // recognized as an UNC path by SetPath()
343 wxString pathNonUNC(path, 1, wxString::npos);
344 SetPath(pathNonUNC, format);
345 }
346 else // no UNC complications
347 {
348 SetPath(path, format);
349 }
a7b51bc8
RR
350
351 m_volume = volume;
352 m_ext = ext;
353 m_name = name;
dfecbee5
VZ
354
355 m_hasExt = hasExt;
a7b51bc8
RR
356}
357
f1e77933 358void wxFileName::SetPath( const wxString& pathOrig, wxPathFormat format )
df5ddbca 359{
844f90fb 360 m_dirs.Clear();
90a68369 361
f1e77933 362 if ( pathOrig.empty() )
df5ddbca 363 {
f1e77933
VZ
364 // no path at all
365 m_relative = true;
a2fa5040 366
f1e77933
VZ
367 return;
368 }
90a68369 369
f1e77933 370 format = GetFormat( format );
a2fa5040 371
f1e77933
VZ
372 // 0) deal with possible volume part first
373 wxString volume,
374 path;
375 SplitVolume(pathOrig, &volume, &path, format);
376 if ( !volume.empty() )
377 {
378 m_relative = false;
a2fa5040 379
f1e77933
VZ
380 SetVolume(volume);
381 }
f363e05c 382
f1e77933
VZ
383 // 1) Determine if the path is relative or absolute.
384 wxChar leadingChar = path[0u];
a2fa5040 385
f1e77933
VZ
386 switch (format)
387 {
388 case wxPATH_MAC:
389 m_relative = leadingChar == wxT(':');
390
391 // We then remove a leading ":". The reason is in our
392 // storage form for relative paths:
393 // ":dir:file.txt" actually means "./dir/file.txt" in
394 // DOS notation and should get stored as
395 // (relative) (dir) (file.txt)
396 // "::dir:file.txt" actually means "../dir/file.txt"
397 // stored as (relative) (..) (dir) (file.txt)
398 // This is important only for the Mac as an empty dir
399 // actually means <UP>, whereas under DOS, double
400 // slashes can be ignored: "\\\\" is the same as "\\".
401 if (m_relative)
402 path.erase( 0, 1 );
403 break;
a2fa5040 404
f1e77933
VZ
405 case wxPATH_VMS:
406 // TODO: what is the relative path format here?
407 m_relative = false;
408 break;
90a68369 409
f1e77933
VZ
410 default:
411 wxFAIL_MSG( _T("Unknown path format") );
412 // !! Fall through !!
90a68369 413
f1e77933
VZ
414 case wxPATH_UNIX:
415 // the paths of the form "~" or "~username" are absolute
416 m_relative = leadingChar != wxT('/') && leadingChar != _T('~');
417 break;
353f41cb 418
f1e77933
VZ
419 case wxPATH_DOS:
420 m_relative = !IsPathSeparator(leadingChar, format);
421 break;
844f90fb 422
df5ddbca 423 }
f1e77933
VZ
424
425 // 2) Break up the path into its members. If the original path
426 // was just "/" or "\\", m_dirs will be empty. We know from
427 // the m_relative field, if this means "nothing" or "root dir".
428
429 wxStringTokenizer tn( path, GetPathSeparators(format) );
430
431 while ( tn.HasMoreTokens() )
a7b51bc8 432 {
f1e77933
VZ
433 wxString token = tn.GetNextToken();
434
435 // Remove empty token under DOS and Unix, interpret them
436 // as .. under Mac.
437 if (token.empty())
438 {
439 if (format == wxPATH_MAC)
440 m_dirs.Add( wxT("..") );
441 // else ignore
442 }
443 else
444 {
445 m_dirs.Add( token );
446 }
a7b51bc8 447 }
844f90fb
VZ
448}
449
450void wxFileName::Assign(const wxString& fullpath,
451 wxPathFormat format)
452{
04c943b1 453 wxString volume, path, name, ext;
dfecbee5
VZ
454 bool hasExt;
455 SplitPath(fullpath, &volume, &path, &name, &ext, &hasExt, format);
844f90fb 456
dfecbee5 457 Assign(volume, path, name, ext, hasExt, format);
844f90fb
VZ
458}
459
81f25632 460void wxFileName::Assign(const wxString& fullpathOrig,
844f90fb
VZ
461 const wxString& fullname,
462 wxPathFormat format)
463{
81f25632
VZ
464 // always recognize fullpath as directory, even if it doesn't end with a
465 // slash
466 wxString fullpath = fullpathOrig;
69858116 467 if ( !fullpath.empty() && !wxEndsWithPathSeparator(fullpath) )
81f25632 468 {
33b97389 469 fullpath += GetPathSeparator(format);
81f25632
VZ
470 }
471
52dbd056 472 wxString volume, path, name, ext;
dfecbee5 473 bool hasExt;
81f25632
VZ
474
475 // do some consistency checks in debug mode: the name should be really just
353f41cb 476 // the filename and the path should be really just a path
81f25632 477#ifdef __WXDEBUG__
dfecbee5 478 wxString volDummy, pathDummy, nameDummy, extDummy;
81f25632 479
dfecbee5 480 SplitPath(fullname, &volDummy, &pathDummy, &name, &ext, &hasExt, format);
81f25632 481
dfecbee5 482 wxASSERT_MSG( volDummy.empty() && pathDummy.empty(),
81f25632
VZ
483 _T("the file name shouldn't contain the path") );
484
485 SplitPath(fullpath, &volume, &path, &nameDummy, &extDummy, format);
486
487 wxASSERT_MSG( nameDummy.empty() && extDummy.empty(),
488 _T("the path shouldn't contain file name nor extension") );
489
490#else // !__WXDEBUG__
284be59b
VZ
491 SplitPath(fullname, NULL /* no volume */, NULL /* no path */,
492 &name, &ext, &hasExt, format);
52dbd056 493 SplitPath(fullpath, &volume, &path, NULL, NULL, format);
81f25632 494#endif // __WXDEBUG__/!__WXDEBUG__
844f90fb 495
dfecbee5 496 Assign(volume, path, name, ext, hasExt, format);
52dbd056
VZ
497}
498
4c2deb19
VZ
499void wxFileName::Assign(const wxString& pathOrig,
500 const wxString& name,
501 const wxString& ext,
502 wxPathFormat format)
503{
504 wxString volume,
505 path;
506 SplitVolume(pathOrig, &volume, &path, format);
507
508 Assign(volume, path, name, ext, format);
509}
510
52dbd056
VZ
511void wxFileName::AssignDir(const wxString& dir, wxPathFormat format)
512{
b494c48b 513 Assign(dir, wxEmptyString, format);
844f90fb
VZ
514}
515
516void wxFileName::Clear()
517{
518 m_dirs.Clear();
04c943b1
VZ
519
520 m_volume =
844f90fb
VZ
521 m_name =
522 m_ext = wxEmptyString;
fb969475
VZ
523
524 // we don't have any absolute path for now
f363e05c 525 m_relative = true;
dfecbee5
VZ
526
527 // nor any extension
528 m_hasExt = false;
844f90fb
VZ
529}
530
531/* static */
520200fd 532wxFileName wxFileName::FileName(const wxString& file, wxPathFormat format)
844f90fb 533{
520200fd 534 return wxFileName(file, format);
844f90fb
VZ
535}
536
537/* static */
520200fd 538wxFileName wxFileName::DirName(const wxString& dir, wxPathFormat format)
844f90fb
VZ
539{
540 wxFileName fn;
520200fd 541 fn.AssignDir(dir, format);
844f90fb 542 return fn;
df5ddbca
RR
543}
544
844f90fb
VZ
545// ----------------------------------------------------------------------------
546// existence tests
547// ----------------------------------------------------------------------------
548
8e41796c 549bool wxFileName::FileExists() const
df5ddbca 550{
a35b27b1
RR
551 return wxFileName::FileExists( GetFullPath() );
552}
553
554bool wxFileName::FileExists( const wxString &file )
555{
556 return ::wxFileExists( file );
df5ddbca
RR
557}
558
8e41796c 559bool wxFileName::DirExists() const
df5ddbca 560{
db759dde 561 return wxFileName::DirExists( GetPath() );
a35b27b1
RR
562}
563
564bool wxFileName::DirExists( const wxString &dir )
565{
da865fdd 566 return ::wxDirExists( dir );
df5ddbca
RR
567}
568
844f90fb
VZ
569// ----------------------------------------------------------------------------
570// CWD and HOME stuff
571// ----------------------------------------------------------------------------
572
6f91bc33 573void wxFileName::AssignCwd(const wxString& volume)
df5ddbca 574{
6f91bc33 575 AssignDir(wxFileName::GetCwd(volume));
a35b27b1
RR
576}
577
844f90fb 578/* static */
6f91bc33 579wxString wxFileName::GetCwd(const wxString& volume)
a35b27b1 580{
6f91bc33
VZ
581 // if we have the volume, we must get the current directory on this drive
582 // and to do this we have to chdir to this volume - at least under Windows,
583 // I don't know how to get the current drive on another volume elsewhere
584 // (TODO)
585 wxString cwdOld;
586 if ( !volume.empty() )
587 {
588 cwdOld = wxGetCwd();
589 SetCwd(volume + GetVolumeSeparator());
590 }
591
592 wxString cwd = ::wxGetCwd();
593
594 if ( !volume.empty() )
595 {
596 SetCwd(cwdOld);
597 }
ae4d7004 598
6f91bc33 599 return cwd;
a35b27b1
RR
600}
601
602bool wxFileName::SetCwd()
603{
db759dde 604 return wxFileName::SetCwd( GetPath() );
df5ddbca
RR
605}
606
a35b27b1 607bool wxFileName::SetCwd( const wxString &cwd )
df5ddbca 608{
a35b27b1 609 return ::wxSetWorkingDirectory( cwd );
df5ddbca
RR
610}
611
a35b27b1
RR
612void wxFileName::AssignHomeDir()
613{
844f90fb 614 AssignDir(wxFileName::GetHomeDir());
a35b27b1 615}
844f90fb 616
a35b27b1
RR
617wxString wxFileName::GetHomeDir()
618{
619 return ::wxGetHomeDir();
620}
844f90fb 621
68351053 622
b70a2866
MW
623// ----------------------------------------------------------------------------
624// CreateTempFileName
625// ----------------------------------------------------------------------------
626
627#if wxUSE_FILE || wxUSE_FFILE
628
629
630#if !defined wx_fdopen && defined HAVE_FDOPEN
631 #define wx_fdopen fdopen
632#endif
633
634// NB: GetTempFileName() under Windows creates the file, so using
635// O_EXCL there would fail
636#ifdef __WINDOWS__
637 #define wxOPEN_EXCL 0
638#else
639 #define wxOPEN_EXCL O_EXCL
640#endif
641
642
643#ifdef wxOpenOSFHandle
644#define WX_HAVE_DELETE_ON_CLOSE
645// On Windows create a file with the FILE_FLAGS_DELETE_ON_CLOSE flags.
646//
647static int wxOpenWithDeleteOnClose(const wxString& filename)
df5ddbca 648{
b70a2866
MW
649 DWORD access = GENERIC_READ | GENERIC_WRITE;
650
651 DWORD disposition = OPEN_ALWAYS;
652
653 DWORD attributes = FILE_ATTRIBUTE_TEMPORARY |
654 FILE_FLAG_DELETE_ON_CLOSE;
655
e0a050e3 656 HANDLE h = ::CreateFile(filename.fn_str(), access, 0, NULL,
b70a2866
MW
657 disposition, attributes, NULL);
658
693bfcaf 659 return wxOpenOSFHandle(h, wxO_BINARY);
ade35f11 660}
b70a2866 661#endif // wxOpenOSFHandle
ade35f11 662
b70a2866
MW
663
664// Helper to open the file
665//
666static int wxTempOpen(const wxString& path, bool *deleteOnClose)
667{
668#ifdef WX_HAVE_DELETE_ON_CLOSE
669 if (*deleteOnClose)
670 return wxOpenWithDeleteOnClose(path);
671#endif
672
673 *deleteOnClose = false;
674
675 return wxOpen(path, wxO_BINARY | O_RDWR | O_CREAT | wxOPEN_EXCL, 0600);
676}
677
678
679#if wxUSE_FFILE
680// Helper to open the file and attach it to the wxFFile
681//
682static bool wxTempOpen(wxFFile *file, const wxString& path, bool *deleteOnClose)
ade35f11 683{
b70a2866
MW
684#ifndef wx_fdopen
685 *deleteOnClose = false;
686 return file->Open(path, _T("w+b"));
687#else // wx_fdopen
688 int fd = wxTempOpen(path, deleteOnClose);
693bfcaf 689 if (fd == -1)
b70a2866
MW
690 return false;
691 file->Attach(wx_fdopen(fd, "w+b"));
692 return file->IsOpened();
693#endif // wx_fdopen
694}
695#endif // wxUSE_FFILE
696
697
698#if !wxUSE_FILE
699 #define WXFILEARGS(x, y) y
700#elif !wxUSE_FFILE
701 #define WXFILEARGS(x, y) x
702#else
703 #define WXFILEARGS(x, y) x, y
704#endif
705
706
707// Implementation of wxFileName::CreateTempFileName().
708//
709static wxString wxCreateTempImpl(
710 const wxString& prefix,
711 WXFILEARGS(wxFile *fileTemp, wxFFile *ffileTemp),
712 bool *deleteOnClose = NULL)
713{
714#if wxUSE_FILE && wxUSE_FFILE
715 wxASSERT(fileTemp == NULL || ffileTemp == NULL);
716#endif
ade35f11 717 wxString path, dir, name;
b70a2866
MW
718 bool wantDeleteOnClose = false;
719
720 if (deleteOnClose)
721 {
722 // set the result to false initially
723 wantDeleteOnClose = *deleteOnClose;
724 *deleteOnClose = false;
725 }
726 else
727 {
728 // easier if it alwasys points to something
729 deleteOnClose = &wantDeleteOnClose;
730 }
ade35f11
VZ
731
732 // use the directory specified by the prefix
b70a2866 733 wxFileName::SplitPath(prefix, &dir, &name, NULL /* extension */);
ade35f11 734
6091caf0
JS
735 if (dir.empty())
736 {
8d7d6dea 737 dir = wxFileName::GetTempDir();
6091caf0
JS
738 }
739
1c193821 740#if defined(__WXWINCE__)
f05ba7ff 741 path = dir + wxT("\\") + name;
1c193821 742 int i = 1;
b70a2866 743 while (wxFileName::FileExists(path))
1c193821 744 {
f05ba7ff 745 path = dir + wxT("\\") + name ;
1c193821
JS
746 path << i;
747 i ++;
748 }
ade35f11 749
1c193821 750#elif defined(__WINDOWS__) && !defined(__WXMICROWIN__)
e0a050e3
VS
751 if ( !::GetTempFileName(dir.fn_str(), name.fn_str(), 0,
752 wxStringBuffer(path, MAX_PATH + 1)) )
ade35f11
VZ
753 {
754 wxLogLastError(_T("GetTempFileName"));
755
756 path.clear();
757 }
ade35f11 758
5a3912f2 759#else // !Windows
ade35f11
VZ
760 path = dir;
761
762 if ( !wxEndsWithPathSeparator(dir) &&
763 (name.empty() || !wxIsPathSeparator(name[0u])) )
764 {
d9f54bb0 765 path += wxFILE_SEP_PATH;
ade35f11
VZ
766 }
767
768 path += name;
769
7070f55b 770#if defined(HAVE_MKSTEMP)
ade35f11
VZ
771 // scratch space for mkstemp()
772 path += _T("XXXXXX");
773
74cf9763 774 // we need to copy the path to the buffer in which mkstemp() can modify it
86501081 775 wxCharBuffer buf(path.fn_str());
74cf9763
VZ
776
777 // cast is safe because the string length doesn't change
ca11abde 778 int fdTemp = mkstemp( (char*)(const char*) buf );
df22f860 779 if ( fdTemp == -1 )
ade35f11
VZ
780 {
781 // this might be not necessary as mkstemp() on most systems should have
782 // already done it but it doesn't hurt neither...
783 path.clear();
784 }
df22f860
VZ
785 else // mkstemp() succeeded
786 {
ca11abde 787 path = wxConvFile.cMB2WX( (const char*) buf );
a62848fd 788
b70a2866 789 #if wxUSE_FILE
df22f860
VZ
790 // avoid leaking the fd
791 if ( fileTemp )
792 {
793 fileTemp->Attach(fdTemp);
794 }
795 else
b70a2866
MW
796 #endif
797
798 #if wxUSE_FFILE
799 if ( ffileTemp )
800 {
801 #ifdef wx_fdopen
802 ffileTemp->Attach(wx_fdopen(fdTemp, "r+b"));
803 #else
804 ffileTemp->Open(path, _T("r+b"));
805 close(fdTemp);
806 #endif
807 }
808 else
809 #endif
810
df22f860
VZ
811 {
812 close(fdTemp);
813 }
814 }
ade35f11
VZ
815#else // !HAVE_MKSTEMP
816
817#ifdef HAVE_MKTEMP
818 // same as above
819 path += _T("XXXXXX");
820
ca11abde 821 wxCharBuffer buf = wxConvFile.cWX2MB( path );
b70a2866 822 if ( !mktemp( (char*)(const char*) buf ) )
ade35f11
VZ
823 {
824 path.clear();
825 }
aed08d79
RR
826 else
827 {
ca11abde 828 path = wxConvFile.cMB2WX( (const char*) buf );
aed08d79 829 }
7070f55b 830#else // !HAVE_MKTEMP (includes __DOS__)
ade35f11 831 // generate the unique file name ourselves
68351053 832 #if !defined(__DOS__) && !defined(__PALMOS__) && (!defined(__MWERKS__) || defined(__DARWIN__) )
ade35f11 833 path << (unsigned int)getpid();
7070f55b 834 #endif
ade35f11
VZ
835
836 wxString pathTry;
837
838 static const size_t numTries = 1000;
839 for ( size_t n = 0; n < numTries; n++ )
840 {
841 // 3 hex digits is enough for numTries == 1000 < 4096
3e778e3b 842 pathTry = path + wxString::Format(_T("%.03x"), (unsigned int) n);
b70a2866 843 if ( !wxFileName::FileExists(pathTry) )
ade35f11
VZ
844 {
845 break;
846 }
847
848 pathTry.clear();
849 }
850
851 path = pathTry;
852#endif // HAVE_MKTEMP/!HAVE_MKTEMP
853
df22f860
VZ
854#endif // HAVE_MKSTEMP/!HAVE_MKSTEMP
855
856#endif // Windows/!Windows
857
858 if ( path.empty() )
859 {
860 wxLogSysError(_("Failed to create a temporary file name"));
861 }
b70a2866 862 else
df22f860 863 {
b70a2866
MW
864 bool ok = true;
865
df22f860 866 // open the file - of course, there is a race condition here, this is
ade35f11 867 // why we always prefer using mkstemp()...
b70a2866
MW
868 #if wxUSE_FILE
869 if ( fileTemp && !fileTemp->IsOpened() )
870 {
871 *deleteOnClose = wantDeleteOnClose;
872 int fd = wxTempOpen(path, deleteOnClose);
873 if (fd != -1)
874 fileTemp->Attach(fd);
875 else
876 ok = false;
877 }
878 #endif
879
880 #if wxUSE_FFILE
881 if ( ffileTemp && !ffileTemp->IsOpened() )
882 {
883 *deleteOnClose = wantDeleteOnClose;
884 ok = wxTempOpen(ffileTemp, path, deleteOnClose);
885 }
886 #endif
887
888 if ( !ok )
ade35f11
VZ
889 {
890 // FIXME: If !ok here should we loop and try again with another
891 // file name? That is the standard recourse if open(O_EXCL)
892 // fails, though of course it should be protected against
893 // possible infinite looping too.
894
895 wxLogError(_("Failed to open temporary file."));
896
897 path.clear();
898 }
899 }
ade35f11
VZ
900
901 return path;
df5ddbca
RR
902}
903
b70a2866
MW
904
905static bool wxCreateTempImpl(
906 const wxString& prefix,
907 WXFILEARGS(wxFile *fileTemp, wxFFile *ffileTemp),
908 wxString *name)
909{
910 bool deleteOnClose = true;
911
912 *name = wxCreateTempImpl(prefix,
913 WXFILEARGS(fileTemp, ffileTemp),
914 &deleteOnClose);
915
916 bool ok = !name->empty();
917
918 if (deleteOnClose)
919 name->clear();
920#ifdef __UNIX__
921 else if (ok && wxRemoveFile(*name))
922 name->clear();
923#endif
924
925 return ok;
926}
927
928
929static void wxAssignTempImpl(
930 wxFileName *fn,
931 const wxString& prefix,
932 WXFILEARGS(wxFile *fileTemp, wxFFile *ffileTemp))
933{
934 wxString tempname;
935 tempname = wxCreateTempImpl(prefix, WXFILEARGS(fileTemp, ffileTemp));
936
937 if ( tempname.empty() )
938 {
939 // error, failed to get temp file name
940 fn->Clear();
941 }
942 else // ok
943 {
944 fn->Assign(tempname);
945 }
946}
947
948
949void wxFileName::AssignTempFileName(const wxString& prefix)
950{
951 wxAssignTempImpl(this, prefix, WXFILEARGS(NULL, NULL));
952}
953
954/* static */
955wxString wxFileName::CreateTempFileName(const wxString& prefix)
956{
957 return wxCreateTempImpl(prefix, WXFILEARGS(NULL, NULL));
958}
959
960#endif // wxUSE_FILE || wxUSE_FFILE
961
962
963#if wxUSE_FILE
964
965wxString wxCreateTempFileName(const wxString& prefix,
966 wxFile *fileTemp,
967 bool *deleteOnClose)
968{
969 return wxCreateTempImpl(prefix, WXFILEARGS(fileTemp, NULL), deleteOnClose);
970}
971
972bool wxCreateTempFile(const wxString& prefix,
973 wxFile *fileTemp,
974 wxString *name)
975{
976 return wxCreateTempImpl(prefix, WXFILEARGS(fileTemp, NULL), name);
977}
978
979void wxFileName::AssignTempFileName(const wxString& prefix, wxFile *fileTemp)
980{
981 wxAssignTempImpl(this, prefix, WXFILEARGS(fileTemp, NULL));
982}
983
984/* static */
985wxString
986wxFileName::CreateTempFileName(const wxString& prefix, wxFile *fileTemp)
987{
988 return wxCreateTempFileName(prefix, fileTemp);
989}
990
68351053
WS
991#endif // wxUSE_FILE
992
b70a2866
MW
993
994#if wxUSE_FFILE
995
996wxString wxCreateTempFileName(const wxString& prefix,
997 wxFFile *fileTemp,
998 bool *deleteOnClose)
999{
1000 return wxCreateTempImpl(prefix, WXFILEARGS(NULL, fileTemp), deleteOnClose);
1001}
1002
1003bool wxCreateTempFile(const wxString& prefix,
1004 wxFFile *fileTemp,
1005 wxString *name)
1006{
1007 return wxCreateTempImpl(prefix, WXFILEARGS(NULL, fileTemp), name);
1008
1009}
1010
1011void wxFileName::AssignTempFileName(const wxString& prefix, wxFFile *fileTemp)
1012{
1013 wxAssignTempImpl(this, prefix, WXFILEARGS(NULL, fileTemp));
1014}
1015
1016/* static */
1017wxString
1018wxFileName::CreateTempFileName(const wxString& prefix, wxFFile *fileTemp)
1019{
1020 return wxCreateTempFileName(prefix, fileTemp);
1021}
1022
1023#endif // wxUSE_FFILE
1024
1025
844f90fb
VZ
1026// ----------------------------------------------------------------------------
1027// directory operations
1028// ----------------------------------------------------------------------------
1029
8758875e
VZ
1030// helper of GetTempDir(): check if the given directory exists and return it if
1031// it does or an empty string otherwise
1032namespace
8d7d6dea 1033{
8d7d6dea 1034
8758875e
VZ
1035wxString CheckIfDirExists(const wxString& dir)
1036{
1037 return wxFileName::DirExists(dir) ? dir : wxString();
1038}
1039
1040} // anonymous namespace
1041
1042wxString wxFileName::GetTempDir()
1043{
1044 // first try getting it from environment: this allows overriding the values
1045 // used by default if the user wants to create temporary files in another
1046 // directory
1047 wxString dir = CheckIfDirExists(wxGetenv("TMPDIR"));
1048 if ( dir.empty() )
8d7d6dea 1049 {
8758875e
VZ
1050 dir = CheckIfDirExists(wxGetenv("TMP"));
1051 if ( dir.empty() )
1052 dir = CheckIfDirExists(wxGetenv("TEMP"));
8d7d6dea 1053 }
8d7d6dea 1054
8758875e 1055 // if no environment variables are set, use the system default
8d7d6dea
JS
1056 if ( dir.empty() )
1057 {
8758875e
VZ
1058#if defined(__WXWINCE__)
1059 dir = CheckIfDirExists(wxT("\\temp"));
1060#elif defined(__WINDOWS__) && !defined(__WXMICROWIN__)
8d7d6dea
JS
1061 if ( !::GetTempPath(MAX_PATH, wxStringBuffer(dir, MAX_PATH + 1)) )
1062 {
1063 wxLogLastError(_T("GetTempPath"));
1064 }
8758875e
VZ
1065#elif defined(__WXMAC__) && wxOSX_USE_CARBON
1066 dir = wxMacFindFolder(short(kOnSystemDisk), kTemporaryFolderType, kCreateFolder);
1067#endif // systems with native way
8d7d6dea 1068 }
8d7d6dea 1069
8758875e 1070 // fall back to hard coded value
8d7d6dea
JS
1071 if ( dir.empty() )
1072 {
8758875e
VZ
1073#ifdef __UNIX_LIKE__
1074 dir = CheckIfDirExists("/tmp");
1075 if ( dir.empty() )
1076#endif // __UNIX_LIKE__
1077 dir = ".";
8d7d6dea 1078 }
8d7d6dea
JS
1079
1080 return dir;
1081}
1082
1527281e 1083bool wxFileName::Mkdir( int perm, int flags )
a35b27b1 1084{
db759dde 1085 return wxFileName::Mkdir(GetPath(), perm, flags);
a35b27b1
RR
1086}
1087
1527281e 1088bool wxFileName::Mkdir( const wxString& dir, int perm, int flags )
df5ddbca 1089{
1527281e 1090 if ( flags & wxPATH_MKDIR_FULL )
f0ce3409 1091 {
1527281e
VZ
1092 // split the path in components
1093 wxFileName filename;
1094 filename.AssignDir(dir);
f0ce3409 1095
f0ce3409 1096 wxString currPath;
0ea621cc
VZ
1097 if ( filename.HasVolume())
1098 {
1527281e 1099 currPath << wxGetVolumeString(filename.GetVolume(), wxPATH_NATIVE);
0ea621cc 1100 }
f0ce3409 1101
1527281e
VZ
1102 wxArrayString dirs = filename.GetDirs();
1103 size_t count = dirs.GetCount();
1104 for ( size_t i = 0; i < count; i++ )
1105 {
e0d81eac 1106 if ( i > 0 || filename.IsAbsolute() )
f0ce3409 1107 currPath += wxFILE_SEP_PATH;
1527281e 1108 currPath += dirs[i];
f0ce3409
JS
1109
1110 if (!DirExists(currPath))
1527281e 1111 {
f0ce3409 1112 if (!wxMkdir(currPath, perm))
1527281e
VZ
1113 {
1114 // no need to try creating further directories
f363e05c 1115 return false;
1527281e
VZ
1116 }
1117 }
f0ce3409
JS
1118 }
1119
f363e05c 1120 return true;
f0ce3409
JS
1121
1122 }
1527281e
VZ
1123
1124 return ::wxMkdir( dir, perm );
df5ddbca
RR
1125}
1126
110c5094 1127bool wxFileName::Rmdir(int flags)
df5ddbca 1128{
110c5094 1129 return wxFileName::Rmdir( GetPath(), flags );
df5ddbca
RR
1130}
1131
110c5094 1132bool wxFileName::Rmdir(const wxString& dir, int flags)
df5ddbca 1133{
110c5094
VZ
1134#ifdef __WXMSW__
1135 if ( flags & wxPATH_RMDIR_RECURSIVE )
1136 {
1137 // SHFileOperation needs double null termination string
1138 // but without separator at the end of the path
1139 wxString path(dir);
1140 if ( path.Last() == wxFILE_SEP_PATH )
1141 path.RemoveLast();
1142 path += _T('\0');
1143
1144 SHFILEOPSTRUCT fileop;
1145 wxZeroMemory(fileop);
1146 fileop.wFunc = FO_DELETE;
1147 fileop.pFrom = path.fn_str();
1148 fileop.fFlags = FOF_SILENT | FOF_NOCONFIRMATION;
1149 #ifndef __WXWINCE__
1150 // FOF_NOERRORUI is not defined in WinCE
1151 fileop.fFlags |= FOF_NOERRORUI;
1152 #endif
1153
1154 int ret = SHFileOperation(&fileop);
1155 if ( ret != 0 )
1156 {
1157 // SHFileOperation may return non-Win32 error codes, so the error
1158 // message can be incorrect
1159 wxLogApiError(_T("SHFileOperation"), ret);
1160 return false;
1161 }
1162
1163 return true;
1164 }
1165 else if ( flags & wxPATH_RMDIR_FULL )
1166#else // !__WXMSW__
1167 if ( flags != 0 ) // wxPATH_RMDIR_FULL or wxPATH_RMDIR_RECURSIVE
1168#endif // !__WXMSW__
1169 {
1170 wxString path(dir);
1171 if ( path.Last() != wxFILE_SEP_PATH )
1172 path += wxFILE_SEP_PATH;
1173
1174 wxDir d(path);
1175
1176 if ( !d.IsOpened() )
1177 return false;
1178
1179 wxString filename;
1180
1181 // first delete all subdirectories
1182 bool cont = d.GetFirst(&filename, "", wxDIR_DIRS | wxDIR_HIDDEN);
1183 while ( cont )
1184 {
1185 wxFileName::Rmdir(path + filename, flags);
1186 cont = d.GetNext(&filename);
1187 }
1188
1189#ifndef __WXMSW__
1190 if ( flags & wxPATH_RMDIR_RECURSIVE )
1191 {
1192 // delete all files too
1193 cont = d.GetFirst(&filename, "", wxDIR_FILES | wxDIR_HIDDEN);
1194 while ( cont )
1195 {
1196 ::wxRemoveFile(path + filename);
1197 cont = d.GetNext(&filename);
1198 }
1199 }
1200#endif // !__WXMSW__
1201 }
1202
1203 return ::wxRmdir(dir);
df5ddbca
RR
1204}
1205
844f90fb
VZ
1206// ----------------------------------------------------------------------------
1207// path normalization
1208// ----------------------------------------------------------------------------
1209
32a0d013 1210bool wxFileName::Normalize(int flags,
844f90fb
VZ
1211 const wxString& cwd,
1212 wxPathFormat format)
a35b27b1 1213{
05e1201c
VZ
1214 // deal with env vars renaming first as this may seriously change the path
1215 if ( flags & wxPATH_NORM_ENV_VARS )
1216 {
1217 wxString pathOrig = GetFullPath(format);
1218 wxString path = wxExpandEnvVars(pathOrig);
1219 if ( path != pathOrig )
1220 {
1221 Assign(path);
1222 }
1223 }
1224
844f90fb
VZ
1225 // the existing path components
1226 wxArrayString dirs = GetDirs();
1227
1228 // the path to prepend in front to make the path absolute
1229 wxFileName curDir;
1230
1231 format = GetFormat(format);
ae4d7004 1232
bf7f7793 1233 // set up the directory to use for making the path absolute later
a2fa5040 1234 if ( (flags & wxPATH_NORM_ABSOLUTE) && !IsAbsolute(format) )
a35b27b1 1235 {
844f90fb 1236 if ( cwd.empty() )
6f91bc33
VZ
1237 {
1238 curDir.AssignCwd(GetVolume());
1239 }
1240 else // cwd provided
1241 {
844f90fb 1242 curDir.AssignDir(cwd);
6f91bc33 1243 }
a35b27b1 1244 }
ae4d7004 1245
844f90fb
VZ
1246 // handle ~ stuff under Unix only
1247 if ( (format == wxPATH_UNIX) && (flags & wxPATH_NORM_TILDE) )
a35b27b1 1248 {
844f90fb
VZ
1249 if ( !dirs.IsEmpty() )
1250 {
1251 wxString dir = dirs[0u];
1252 if ( !dir.empty() && dir[0u] == _T('~') )
1253 {
bf7f7793 1254 // to make the path absolute use the home directory
844f90fb
VZ
1255 curDir.AssignDir(wxGetUserHome(dir.c_str() + 1));
1256
bf7f7793
RR
1257 // if we are expanding the tilde, then this path
1258 // *should* be already relative (since we checked for
1259 // the tilde only in the first char of the first dir);
1260 // if m_relative==false, it's because it was initialized
1261 // from a string which started with /~; in that case
1262 // we reach this point but then need m_relative=true
1263 // for relative->absolute expansion later
1264 m_relative = true;
1265
da2fd5ac 1266 dirs.RemoveAt(0u);
844f90fb
VZ
1267 }
1268 }
a35b27b1 1269 }
844f90fb 1270
52dbd056 1271 // transform relative path into abs one
844f90fb 1272 if ( curDir.IsOk() )
a35b27b1 1273 {
bf7f7793
RR
1274 // this path may be relative because it doesn't have the volume name
1275 // and still have m_relative=true; in this case we shouldn't modify
1276 // our directory components but just set the current volume
1277 if ( !HasVolume() && curDir.HasVolume() )
844f90fb 1278 {
bf7f7793
RR
1279 SetVolume(curDir.GetVolume());
1280
1281 if ( !m_relative )
1282 {
1283 // yes, it was the case - we don't need curDir then
1284 curDir.Clear();
1285 }
844f90fb
VZ
1286 }
1287
bf7f7793
RR
1288 // finally, prepend curDir to the dirs array
1289 wxArrayString dirsNew = curDir.GetDirs();
1290 WX_PREPEND_ARRAY(dirs, dirsNew);
1291
1292 // if we used e.g. tilde expansion previously and wxGetUserHome didn't
1293 // return for some reason an absolute path, then curDir maybe not be absolute!
1294 if ( curDir.IsAbsolute(format) )
1295 {
1296 // we have prepended an absolute path and thus we are now an absolute
1297 // file name too
1298 m_relative = false;
1299 }
1300 // else if (flags & wxPATH_NORM_ABSOLUTE):
1301 // should we warn the user that we didn't manage to make the path absolute?
a35b27b1 1302 }
844f90fb
VZ
1303
1304 // now deal with ".", ".." and the rest
1305 m_dirs.Empty();
1306 size_t count = dirs.GetCount();
1307 for ( size_t n = 0; n < count; n++ )
a35b27b1 1308 {
844f90fb
VZ
1309 wxString dir = dirs[n];
1310
2bc60417 1311 if ( flags & wxPATH_NORM_DOTS )
844f90fb
VZ
1312 {
1313 if ( dir == wxT(".") )
1314 {
1315 // just ignore
1316 continue;
1317 }
1318
1319 if ( dir == wxT("..") )
1320 {
1321 if ( m_dirs.IsEmpty() )
1322 {
1323 wxLogError(_("The path '%s' contains too many \"..\"!"),
1324 GetFullPath().c_str());
f363e05c 1325 return false;
844f90fb
VZ
1326 }
1327
ae4d7004 1328 m_dirs.RemoveAt(m_dirs.GetCount() - 1);
844f90fb
VZ
1329 continue;
1330 }
1331 }
1332
844f90fb 1333 m_dirs.Add(dir);
a35b27b1 1334 }
a62848fd 1335
6bda7391 1336#if defined(__WIN32__) && !defined(__WXWINCE__) && wxUSE_OLE
21f60945
JS
1337 if ( (flags & wxPATH_NORM_SHORTCUT) )
1338 {
1339 wxString filename;
1340 if (GetShortcutTarget(GetFullPath(format), filename))
1341 {
21f60945
JS
1342 m_relative = false;
1343 Assign(filename);
1344 }
1345 }
1346#endif
844f90fb 1347
9a0c5c01
VZ
1348#if defined(__WIN32__)
1349 if ( (flags & wxPATH_NORM_LONG) && (format == wxPATH_DOS) )
844f90fb 1350 {
9a0c5c01
VZ
1351 Assign(GetLongPath());
1352 }
1353#endif // Win32
844f90fb 1354
9a0c5c01
VZ
1355 // Change case (this should be kept at the end of the function, to ensure
1356 // that the path doesn't change any more after we normalize its case)
1357 if ( (flags & wxPATH_NORM_CASE) && !IsCaseSensitive(format) )
1358 {
55268a3a 1359 m_volume.MakeLower();
844f90fb
VZ
1360 m_name.MakeLower();
1361 m_ext.MakeLower();
844f90fb 1362
9a0c5c01
VZ
1363 // directory entries must be made lower case as well
1364 count = m_dirs.GetCount();
1365 for ( size_t i = 0; i < count; i++ )
1366 {
1367 m_dirs[i].MakeLower();
1368 }
9e9b65c1 1369 }
9e9b65c1 1370
f363e05c 1371 return true;
a2fa5040
VZ
1372}
1373
395f3aa8
FM
1374#ifndef __WXWINCE__
1375bool wxFileName::ReplaceEnvVariable(const wxString& envname,
1376 const wxString& replacementFmtString,
1377 wxPathFormat format)
1378{
1379 // look into stringForm for the contents of the given environment variable
1380 wxString val;
1381 if (envname.empty() ||
1382 !wxGetEnv(envname, &val))
1383 return false;
1384 if (val.empty())
1385 return false;
1386
1387 wxString stringForm = GetPath(wxPATH_GET_VOLUME, format);
1388 // do not touch the file name and the extension
1389
1390 wxString replacement = wxString::Format(replacementFmtString, envname);
1391 stringForm.Replace(val, replacement);
1392
1393 // Now assign ourselves the modified path:
1394 Assign(stringForm, GetFullName(), format);
1395
1396 return true;
1397}
1398#endif
1399
1400bool wxFileName::ReplaceHomeDir(wxPathFormat format)
1401{
1402 wxString homedir = wxGetHomeDir();
1403 if (homedir.empty())
1404 return false;
1405
1406 wxString stringForm = GetPath(wxPATH_GET_VOLUME, format);
1407 // do not touch the file name and the extension
1408
1409 stringForm.Replace(homedir, "~");
1410
1411 // Now assign ourselves the modified path:
1412 Assign(stringForm, GetFullName(), format);
1413
1414 return true;
1415}
1416
21f60945
JS
1417// ----------------------------------------------------------------------------
1418// get the shortcut target
1419// ----------------------------------------------------------------------------
1420
5671b3b6
JS
1421// WinCE (3) doesn't have CLSID_ShellLink, IID_IShellLink definitions.
1422// The .lnk file is a plain text file so it should be easy to
1423// make it work. Hint from Google Groups:
1424// "If you open up a lnk file, you'll see a
1425// number, followed by a pound sign (#), followed by more text. The
1426// number is the number of characters that follows the pound sign. The
1427// characters after the pound sign are the command line (which _can_
1428// include arguments) to be executed. Any path (e.g. \windows\program
1429// files\myapp.exe) that includes spaces needs to be enclosed in
1430// quotation marks."
1431
6bda7391 1432#if defined(__WIN32__) && !defined(__WXWINCE__) && wxUSE_OLE
5671b3b6
JS
1433// The following lines are necessary under WinCE
1434// #include "wx/msw/private.h"
1435// #include <ole2.h>
21f60945 1436#include <shlobj.h>
5671b3b6
JS
1437#if defined(__WXWINCE__)
1438#include <shlguid.h>
1439#endif
21f60945 1440
cea0869c
VZ
1441bool wxFileName::GetShortcutTarget(const wxString& shortcutPath,
1442 wxString& targetFilename,
1443 wxString* arguments)
21f60945 1444{
21f60945 1445 wxString path, file, ext;
bd365871 1446 wxFileName::SplitPath(shortcutPath, & path, & file, & ext);
a62848fd
WS
1447
1448 HRESULT hres;
1449 IShellLink* psl;
1450 bool success = false;
21f60945
JS
1451
1452 // Assume it's not a shortcut if it doesn't end with lnk
489f6cf7 1453 if (ext.CmpNoCase(wxT("lnk"))!=0)
a62848fd
WS
1454 return false;
1455
1456 // create a ShellLink object
1457 hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
1458 IID_IShellLink, (LPVOID*) &psl);
1459
1460 if (SUCCEEDED(hres))
1461 {
1462 IPersistFile* ppf;
1463 hres = psl->QueryInterface( IID_IPersistFile, (LPVOID *) &ppf);
1464 if (SUCCEEDED(hres))
1465 {
1466 WCHAR wsz[MAX_PATH];
1467
1468 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, shortcutPath.mb_str(), -1, wsz,
1469 MAX_PATH);
1470
1471 hres = ppf->Load(wsz, 0);
cea0869c
VZ
1472 ppf->Release();
1473
a62848fd
WS
1474 if (SUCCEEDED(hres))
1475 {
21f60945 1476 wxChar buf[2048];
59ba321b
JS
1477 // Wrong prototype in early versions
1478#if defined(__MINGW32__) && !wxCHECK_W32API_VERSION(2, 2)
1479 psl->GetPath((CHAR*) buf, 2048, NULL, SLGP_UNCPRIORITY);
1480#else
a62848fd 1481 psl->GetPath(buf, 2048, NULL, SLGP_UNCPRIORITY);
59ba321b 1482#endif
a62848fd 1483 targetFilename = wxString(buf);
21f60945
JS
1484 success = (shortcutPath != targetFilename);
1485
a62848fd 1486 psl->GetArguments(buf, 2048);
21f60945 1487 wxString args(buf);
b494c48b 1488 if (!args.empty() && arguments)
21f60945
JS
1489 {
1490 *arguments = args;
a62848fd
WS
1491 }
1492 }
1493 }
cea0869c
VZ
1494
1495 psl->Release();
a62848fd 1496 }
a62848fd 1497 return success;
21f60945 1498}
cea0869c
VZ
1499
1500#endif // __WIN32__ && !__WXWINCE__
21f60945
JS
1501
1502
a2fa5040
VZ
1503// ----------------------------------------------------------------------------
1504// absolute/relative paths
1505// ----------------------------------------------------------------------------
1506
1507bool wxFileName::IsAbsolute(wxPathFormat format) const
1508{
1509 // if our path doesn't start with a path separator, it's not an absolute
1510 // path
1511 if ( m_relative )
f363e05c 1512 return false;
a2fa5040
VZ
1513
1514 if ( !GetVolumeSeparator(format).empty() )
1515 {
1516 // this format has volumes and an absolute path must have one, it's not
1517 // enough to have the full path to bean absolute file under Windows
1518 if ( GetVolume().empty() )
f363e05c 1519 return false;
a2fa5040
VZ
1520 }
1521
f363e05c 1522 return true;
a35b27b1
RR
1523}
1524
f7d886af
VZ
1525bool wxFileName::MakeRelativeTo(const wxString& pathBase, wxPathFormat format)
1526{
cef9731a 1527 wxFileName fnBase = wxFileName::DirName(pathBase, format);
f7d886af
VZ
1528
1529 // get cwd only once - small time saving
1530 wxString cwd = wxGetCwd();
b5b62eea
JS
1531 Normalize(wxPATH_NORM_ALL & ~wxPATH_NORM_CASE, cwd, format);
1532 fnBase.Normalize(wxPATH_NORM_ALL & ~wxPATH_NORM_CASE, cwd, format);
f7d886af
VZ
1533
1534 bool withCase = IsCaseSensitive(format);
1535
1536 // we can't do anything if the files live on different volumes
1537 if ( !GetVolume().IsSameAs(fnBase.GetVolume(), withCase) )
1538 {
1539 // nothing done
f363e05c 1540 return false;
f7d886af
VZ
1541 }
1542
1543 // same drive, so we don't need our volume
1544 m_volume.clear();
1545
1546 // remove common directories starting at the top
1547 while ( !m_dirs.IsEmpty() && !fnBase.m_dirs.IsEmpty() &&
1548 m_dirs[0u].IsSameAs(fnBase.m_dirs[0u], withCase) )
1549 {
ae4d7004
VZ
1550 m_dirs.RemoveAt(0);
1551 fnBase.m_dirs.RemoveAt(0);
f7d886af
VZ
1552 }
1553
1554 // add as many ".." as needed
1555 size_t count = fnBase.m_dirs.GetCount();
1556 for ( size_t i = 0; i < count; i++ )
1557 {
1558 m_dirs.Insert(wxT(".."), 0u);
1559 }
90a68369 1560
2db991f4
VZ
1561 if ( format == wxPATH_UNIX || format == wxPATH_DOS )
1562 {
1563 // a directory made relative with respect to itself is '.' under Unix
1564 // and DOS, by definition (but we don't have to insert "./" for the
1565 // files)
1566 if ( m_dirs.IsEmpty() && IsDir() )
1567 {
1568 m_dirs.Add(_T('.'));
0ea621cc 1569 }
2db991f4
VZ
1570 }
1571
f363e05c 1572 m_relative = true;
f7d886af
VZ
1573
1574 // we were modified
f363e05c 1575 return true;
f7d886af
VZ
1576}
1577
844f90fb
VZ
1578// ----------------------------------------------------------------------------
1579// filename kind tests
1580// ----------------------------------------------------------------------------
1581
2b5f62a0 1582bool wxFileName::SameAs(const wxFileName& filepath, wxPathFormat format) const
df5ddbca 1583{
844f90fb
VZ
1584 wxFileName fn1 = *this,
1585 fn2 = filepath;
1586
1587 // get cwd only once - small time saving
1588 wxString cwd = wxGetCwd();
55268a3a
VZ
1589 fn1.Normalize(wxPATH_NORM_ALL | wxPATH_NORM_CASE, cwd, format);
1590 fn2.Normalize(wxPATH_NORM_ALL | wxPATH_NORM_CASE, cwd, format);
844f90fb
VZ
1591
1592 if ( fn1.GetFullPath() == fn2.GetFullPath() )
f363e05c 1593 return true;
844f90fb
VZ
1594
1595 // TODO: compare inodes for Unix, this works even when filenames are
1596 // different but files are the same (symlinks) (VZ)
1597
f363e05c 1598 return false;
df5ddbca
RR
1599}
1600
844f90fb 1601/* static */
df5ddbca
RR
1602bool wxFileName::IsCaseSensitive( wxPathFormat format )
1603{
04c943b1
VZ
1604 // only Unix filenames are truely case-sensitive
1605 return GetFormat(format) == wxPATH_UNIX;
df5ddbca
RR
1606}
1607
f363e05c
VZ
1608/* static */
1609wxString wxFileName::GetForbiddenChars(wxPathFormat format)
1610{
1611 // Inits to forbidden characters that are common to (almost) all platforms.
1612 wxString strForbiddenChars = wxT("*?");
1613
1c6f2414 1614 // If asserts, wxPathFormat has been changed. In case of a new path format
f363e05c 1615 // addition, the following code might have to be updated.
1c6f2414 1616 wxCOMPILE_TIME_ASSERT(wxPATH_MAX == 5, wxPathFormatChanged);
f363e05c
VZ
1617 switch ( GetFormat(format) )
1618 {
1619 default :
1620 wxFAIL_MSG( wxT("Unknown path format") );
1621 // !! Fall through !!
1622
1623 case wxPATH_UNIX:
1624 break;
1625
1626 case wxPATH_MAC:
1627 // On a Mac even names with * and ? are allowed (Tested with OS
1628 // 9.2.1 and OS X 10.2.5)
1629 strForbiddenChars = wxEmptyString;
1630 break;
1631
1632 case wxPATH_DOS:
1633 strForbiddenChars += wxT("\\/:\"<>|");
1634 break;
1635
1636 case wxPATH_VMS:
1637 break;
1638 }
1639
1640 return strForbiddenChars;
1641}
1642
04c943b1 1643/* static */
bcfa2b31 1644wxString wxFileName::GetVolumeSeparator(wxPathFormat WXUNUSED_IN_WINCE(format))
844f90fb 1645{
bcfa2b31
WS
1646#ifdef __WXWINCE__
1647 return wxEmptyString;
1648#else
04c943b1
VZ
1649 wxString sepVol;
1650
a385b5df
RR
1651 if ( (GetFormat(format) == wxPATH_DOS) ||
1652 (GetFormat(format) == wxPATH_VMS) )
04c943b1 1653 {
04c943b1
VZ
1654 sepVol = wxFILE_SEP_DSK;
1655 }
a385b5df 1656 //else: leave empty
04c943b1
VZ
1657
1658 return sepVol;
bcfa2b31 1659#endif
844f90fb
VZ
1660}
1661
1662/* static */
1663wxString wxFileName::GetPathSeparators(wxPathFormat format)
1664{
1665 wxString seps;
1666 switch ( GetFormat(format) )
df5ddbca 1667 {
844f90fb 1668 case wxPATH_DOS:
04c943b1
VZ
1669 // accept both as native APIs do but put the native one first as
1670 // this is the one we use in GetFullPath()
1671 seps << wxFILE_SEP_PATH_DOS << wxFILE_SEP_PATH_UNIX;
844f90fb
VZ
1672 break;
1673
1674 default:
f363e05c 1675 wxFAIL_MSG( _T("Unknown wxPATH_XXX style") );
844f90fb
VZ
1676 // fall through
1677
1678 case wxPATH_UNIX:
9e8d8607 1679 seps = wxFILE_SEP_PATH_UNIX;
844f90fb
VZ
1680 break;
1681
1682 case wxPATH_MAC:
9e8d8607 1683 seps = wxFILE_SEP_PATH_MAC;
844f90fb 1684 break;
04c943b1 1685
3c621059
JJ
1686 case wxPATH_VMS:
1687 seps = wxFILE_SEP_PATH_VMS;
1688 break;
df5ddbca
RR
1689 }
1690
844f90fb 1691 return seps;
df5ddbca
RR
1692}
1693
f1e77933
VZ
1694/* static */
1695wxString wxFileName::GetPathTerminators(wxPathFormat format)
1696{
1697 format = GetFormat(format);
1698
1699 // under VMS the end of the path is ']', not the path separator used to
1700 // separate the components
1701 return format == wxPATH_VMS ? wxString(_T(']')) : GetPathSeparators(format);
1702}
1703
844f90fb
VZ
1704/* static */
1705bool wxFileName::IsPathSeparator(wxChar ch, wxPathFormat format)
df5ddbca 1706{
04c943b1 1707 // wxString::Find() doesn't work as expected with NUL - it will always find
2fb5a4ce
VZ
1708 // it, so test for it separately
1709 return ch != _T('\0') && GetPathSeparators(format).Find(ch) != wxNOT_FOUND;
df5ddbca
RR
1710}
1711
844f90fb
VZ
1712// ----------------------------------------------------------------------------
1713// path components manipulation
1714// ----------------------------------------------------------------------------
1715
5bb9aeb2
VZ
1716/* static */ bool wxFileName::IsValidDirComponent(const wxString& dir)
1717{
1718 if ( dir.empty() )
1719 {
1720 wxFAIL_MSG( _T("empty directory passed to wxFileName::InsertDir()") );
1721
1722 return false;
1723 }
1724
1725 const size_t len = dir.length();
1726 for ( size_t n = 0; n < len; n++ )
1727 {
1728 if ( dir[n] == GetVolumeSeparator() || IsPathSeparator(dir[n]) )
1729 {
1730 wxFAIL_MSG( _T("invalid directory component in wxFileName") );
1731
1732 return false;
1733 }
1734 }
1735
1736 return true;
1737}
1738
2458d90b 1739void wxFileName::AppendDir( const wxString& dir )
df5ddbca 1740{
5bb9aeb2
VZ
1741 if ( IsValidDirComponent(dir) )
1742 m_dirs.Add( dir );
df5ddbca
RR
1743}
1744
2458d90b 1745void wxFileName::PrependDir( const wxString& dir )
df5ddbca 1746{
5bb9aeb2 1747 InsertDir(0, dir);
df5ddbca
RR
1748}
1749
2458d90b 1750void wxFileName::InsertDir(size_t before, const wxString& dir)
df5ddbca 1751{
5bb9aeb2 1752 if ( IsValidDirComponent(dir) )
2458d90b 1753 m_dirs.Insert(dir, before);
df5ddbca
RR
1754}
1755
2458d90b 1756void wxFileName::RemoveDir(size_t pos)
df5ddbca 1757{
2458d90b 1758 m_dirs.RemoveAt(pos);
df5ddbca
RR
1759}
1760
844f90fb
VZ
1761// ----------------------------------------------------------------------------
1762// accessors
1763// ----------------------------------------------------------------------------
1764
7124df9b
VZ
1765void wxFileName::SetFullName(const wxString& fullname)
1766{
dfecbee5
VZ
1767 SplitPath(fullname, NULL /* no volume */, NULL /* no path */,
1768 &m_name, &m_ext, &m_hasExt);
7124df9b
VZ
1769}
1770
844f90fb 1771wxString wxFileName::GetFullName() const
a35b27b1 1772{
844f90fb 1773 wxString fullname = m_name;
dfecbee5 1774 if ( m_hasExt )
a35b27b1 1775 {
9e8d8607 1776 fullname << wxFILE_SEP_EXT << m_ext;
a35b27b1 1777 }
a35b27b1 1778
844f90fb 1779 return fullname;
a35b27b1
RR
1780}
1781
33b97389 1782wxString wxFileName::GetPath( int flags, wxPathFormat format ) const
df5ddbca
RR
1783{
1784 format = GetFormat( format );
844f90fb 1785
353f41cb
RR
1786 wxString fullpath;
1787
33b97389
VZ
1788 // return the volume with the path as well if requested
1789 if ( flags & wxPATH_GET_VOLUME )
1790 {
1791 fullpath += wxGetVolumeString(GetVolume(), format);
1792 }
1793
034742fc
VZ
1794 // the leading character
1795 switch ( format )
1796 {
1797 case wxPATH_MAC:
1798 if ( m_relative )
1799 fullpath += wxFILE_SEP_PATH_MAC;
1800 break;
1801
1802 case wxPATH_DOS:
1803 if ( !m_relative )
1804 fullpath += wxFILE_SEP_PATH_DOS;
1805 break;
1806
1807 default:
1808 wxFAIL_MSG( wxT("Unknown path format") );
1809 // fall through
1810
1811 case wxPATH_UNIX:
1812 if ( !m_relative )
1813 {
1814 // normally the absolute file names start with a slash
1815 // with one exception: the ones like "~/foo.bar" don't
1816 // have it
9b3a3820 1817 if ( m_dirs.IsEmpty() || m_dirs[0u] != _T('~') )
034742fc
VZ
1818 {
1819 fullpath += wxFILE_SEP_PATH_UNIX;
1820 }
1821 }
1822 break;
1823
1824 case wxPATH_VMS:
1825 // no leading character here but use this place to unset
1826 // wxPATH_GET_SEPARATOR flag: under VMS it doesn't make sense
1827 // as, if I understand correctly, there should never be a dot
1828 // before the closing bracket
1829 flags &= ~wxPATH_GET_SEPARATOR;
1830 }
1831
1832 if ( m_dirs.empty() )
1833 {
1834 // there is nothing more
1835 return fullpath;
1836 }
1837
1838 // then concatenate all the path components using the path separator
1839 if ( format == wxPATH_VMS )
1840 {
1841 fullpath += wxT('[');
1842 }
1843
5bb9aeb2 1844 const size_t dirCount = m_dirs.GetCount();
034742fc 1845 for ( size_t i = 0; i < dirCount; i++ )
353f41cb 1846 {
034742fc 1847 switch (format)
5bb9aeb2
VZ
1848 {
1849 case wxPATH_MAC:
034742fc
VZ
1850 if ( m_dirs[i] == wxT(".") )
1851 {
1852 // skip appending ':', this shouldn't be done in this
1853 // case as "::" is interpreted as ".." under Unix
1854 continue;
1855 }
2361ce82 1856
034742fc 1857 // convert back from ".." to nothing
489f6cf7 1858 if ( !m_dirs[i].IsSameAs(wxT("..")) )
034742fc 1859 fullpath += m_dirs[i];
5bb9aeb2 1860 break;
2361ce82 1861
5bb9aeb2 1862 default:
034742fc
VZ
1863 wxFAIL_MSG( wxT("Unexpected path format") );
1864 // still fall through
2361ce82 1865
034742fc 1866 case wxPATH_DOS:
5bb9aeb2 1867 case wxPATH_UNIX:
034742fc 1868 fullpath += m_dirs[i];
5bb9aeb2 1869 break;
2361ce82 1870
5bb9aeb2 1871 case wxPATH_VMS:
034742fc 1872 // TODO: What to do with ".." under VMS
353f41cb 1873
034742fc 1874 // convert back from ".." to nothing
489f6cf7 1875 if ( !m_dirs[i].IsSameAs(wxT("..")) )
353f41cb 1876 fullpath += m_dirs[i];
034742fc 1877 break;
4175794e
VZ
1878 }
1879
034742fc
VZ
1880 if ( (flags & wxPATH_GET_SEPARATOR) || (i != dirCount - 1) )
1881 fullpath += GetPathSeparator(format);
df5ddbca 1882 }
034742fc
VZ
1883
1884 if ( format == wxPATH_VMS )
5bb9aeb2 1885 {
034742fc 1886 fullpath += wxT(']');
5bb9aeb2 1887 }
844f90fb 1888
353f41cb 1889 return fullpath;
df5ddbca
RR
1890}
1891
1892wxString wxFileName::GetFullPath( wxPathFormat format ) const
1893{
4175794e
VZ
1894 // we already have a function to get the path
1895 wxString fullpath = GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR,
1896 format);
04c943b1 1897
4175794e 1898 // now just add the file name and extension to it
04c943b1
VZ
1899 fullpath += GetFullName();
1900
1901 return fullpath;
df5ddbca
RR
1902}
1903
9e9b65c1
JS
1904// Return the short form of the path (returns identity on non-Windows platforms)
1905wxString wxFileName::GetShortPath() const
1906{
9e9b65c1 1907 wxString path(GetFullPath());
2f3d9587
VZ
1908
1909#if defined(__WXMSW__) && defined(__WIN32__) && !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
e0a050e3 1910 DWORD sz = ::GetShortPathName(path.fn_str(), NULL, 0);
2f3d9587 1911 if ( sz != 0 )
9e9b65c1 1912 {
2f3d9587
VZ
1913 wxString pathOut;
1914 if ( ::GetShortPathName
75ef5722 1915 (
e0a050e3 1916 path.fn_str(),
de564874 1917 wxStringBuffer(pathOut, sz),
75ef5722 1918 sz
2f3d9587
VZ
1919 ) != 0 )
1920 {
1921 return pathOut;
1922 }
9e9b65c1 1923 }
2f3d9587 1924#endif // Windows
5716a1ab
VZ
1925
1926 return path;
9e9b65c1
JS
1927}
1928
1929// Return the long form of the path (returns identity on non-Windows platforms)
1930wxString wxFileName::GetLongPath() const
1931{
52dbd056
VZ
1932 wxString pathOut,
1933 path = GetFullPath();
1934
b517351b 1935#if defined(__WIN32__) && !defined(__WXWINCE__) && !defined(__WXMICROWIN__)
05e7001c 1936
0e207280 1937#if wxUSE_DYNLIB_CLASS
62dcaed6 1938 typedef DWORD (WINAPI *GET_LONG_PATH_NAME)(const wxChar *, wxChar *, DWORD);
05e7001c 1939
2f3d9587
VZ
1940 // this is MT-safe as in the worst case we're going to resolve the function
1941 // twice -- but as the result is the same in both threads, it's ok
1942 static GET_LONG_PATH_NAME s_pfnGetLongPathName = NULL;
1943 if ( !s_pfnGetLongPathName )
9e9b65c1 1944 {
2f3d9587 1945 static bool s_triedToLoad = false;
2361ce82 1946
2f3d9587 1947 if ( !s_triedToLoad )
05e7001c 1948 {
2f3d9587
VZ
1949 s_triedToLoad = true;
1950
1951 wxDynamicLibrary dllKernel(_T("kernel32"));
1952
4377d3ab
WS
1953 const wxChar* GetLongPathName = _T("GetLongPathName")
1954#if wxUSE_UNICODE
1955 _T("W");
1956#else // ANSI
1957 _T("A");
1958#endif // Unicode/ANSI
1959
1960 if ( dllKernel.HasSymbol(GetLongPathName) )
05e7001c 1961 {
2f3d9587 1962 s_pfnGetLongPathName = (GET_LONG_PATH_NAME)
4377d3ab 1963 dllKernel.GetSymbol(GetLongPathName);
05e7001c 1964 }
2f3d9587
VZ
1965
1966 // note that kernel32.dll can be unloaded, it stays in memory
1967 // anyhow as all Win32 programs link to it and so it's safe to call
1968 // GetLongPathName() even after unloading it
05e7001c 1969 }
9e9b65c1 1970 }
2361ce82 1971
2f3d9587
VZ
1972 if ( s_pfnGetLongPathName )
1973 {
e0a050e3 1974 DWORD dwSize = (*s_pfnGetLongPathName)(path.fn_str(), NULL, 0);
2f3d9587
VZ
1975 if ( dwSize > 0 )
1976 {
1977 if ( (*s_pfnGetLongPathName)
1978 (
e0a050e3 1979 path.fn_str(),
2f3d9587
VZ
1980 wxStringBuffer(pathOut, dwSize),
1981 dwSize
1982 ) != 0 )
1983 {
1984 return pathOut;
1985 }
1986 }
1987 }
0e207280 1988#endif // wxUSE_DYNLIB_CLASS
05e7001c 1989
2f3d9587
VZ
1990 // The OS didn't support GetLongPathName, or some other error.
1991 // We need to call FindFirstFile on each component in turn.
05e7001c 1992
2f3d9587
VZ
1993 WIN32_FIND_DATA findFileData;
1994 HANDLE hFind;
b5b62eea 1995
2f3d9587
VZ
1996 if ( HasVolume() )
1997 pathOut = GetVolume() +
1998 GetVolumeSeparator(wxPATH_DOS) +
1999 GetPathSeparator(wxPATH_DOS);
2000 else
2001 pathOut = wxEmptyString;
05e7001c 2002
2f3d9587
VZ
2003 wxArrayString dirs = GetDirs();
2004 dirs.Add(GetFullName());
77fe02a8 2005
2f3d9587 2006 wxString tmpPath;
5d978d07 2007
2f3d9587
VZ
2008 size_t count = dirs.GetCount();
2009 for ( size_t i = 0; i < count; i++ )
2010 {
ea6319cb
VZ
2011 const wxString& dir = dirs[i];
2012
2f3d9587
VZ
2013 // We're using pathOut to collect the long-name path, but using a
2014 // temporary for appending the last path component which may be
2015 // short-name
ea6319cb
VZ
2016 tmpPath = pathOut + dir;
2017
2018 // We must not process "." or ".." here as they would be (unexpectedly)
2019 // replaced by the corresponding directory names so just leave them
2020 // alone
2021 //
2022 // And we can't pass a drive and root dir to FindFirstFile (VZ: why?)
2023 if ( tmpPath.empty() || dir == '.' || dir == ".." ||
2024 tmpPath.Last() == GetVolumeSeparator(wxPATH_DOS) )
2f3d9587 2025 {
2f3d9587
VZ
2026 tmpPath += wxFILE_SEP_PATH;
2027 pathOut = tmpPath;
2028 continue;
2029 }
05e7001c 2030
e0a050e3 2031 hFind = ::FindFirstFile(tmpPath.fn_str(), &findFileData);
2f3d9587
VZ
2032 if (hFind == INVALID_HANDLE_VALUE)
2033 {
2034 // Error: most likely reason is that path doesn't exist, so
2035 // append any unprocessed parts and return
2036 for ( i += 1; i < count; i++ )
2037 tmpPath += wxFILE_SEP_PATH + dirs[i];
b5b62eea 2038
2f3d9587
VZ
2039 return tmpPath;
2040 }
05e7001c 2041
2f3d9587
VZ
2042 pathOut += findFileData.cFileName;
2043 if ( (i < (count-1)) )
2044 pathOut += wxFILE_SEP_PATH;
52dbd056 2045
2f3d9587 2046 ::FindClose(hFind);
05e7001c 2047 }
52dbd056
VZ
2048#else // !Win32
2049 pathOut = path;
2050#endif // Win32/!Win32
5716a1ab 2051
05e7001c 2052 return pathOut;
9e9b65c1
JS
2053}
2054
df5ddbca
RR
2055wxPathFormat wxFileName::GetFormat( wxPathFormat format )
2056{
2057 if (format == wxPATH_NATIVE)
2058 {
5a3912f2 2059#if defined(__WXMSW__) || defined(__OS2__) || defined(__DOS__)
df5ddbca 2060 format = wxPATH_DOS;
3c621059 2061#elif defined(__VMS)
04c943b1 2062 format = wxPATH_VMS;
844f90fb 2063#else
df5ddbca
RR
2064 format = wxPATH_UNIX;
2065#endif
2066 }
2067 return format;
2068}
a35b27b1 2069
35c2aa4f
VZ
2070#ifdef wxHAS_FILESYSTEM_VOLUMES
2071
2072/* static */
2073wxString wxFileName::GetVolumeString(char drive, int flags)
2074{
2075 wxASSERT_MSG( !(flags & ~wxPATH_GET_SEPARATOR), "invalid flag specified" );
2076
2077 wxString vol(drive);
2078 vol += wxFILE_SEP_DSK;
2079 if ( flags & wxPATH_GET_SEPARATOR )
2080 vol += wxFILE_SEP_PATH;
2081
2082 return vol;
2083}
2084
2085#endif // wxHAS_FILESYSTEM_VOLUMES
2086
9e8d8607
VZ
2087// ----------------------------------------------------------------------------
2088// path splitting function
2089// ----------------------------------------------------------------------------
2090
6f91bc33 2091/* static */
f1e77933
VZ
2092void
2093wxFileName::SplitVolume(const wxString& fullpathWithVolume,
2094 wxString *pstrVolume,
2095 wxString *pstrPath,
2096 wxPathFormat format)
9e8d8607
VZ
2097{
2098 format = GetFormat(format);
2099
04c943b1
VZ
2100 wxString fullpath = fullpathWithVolume;
2101
04c943b1 2102 // special Windows UNC paths hack: transform \\share\path into share:path
9e1c7236 2103 if ( IsUNCPath(fullpath, format) )
9e8d8607 2104 {
9e1c7236 2105 fullpath.erase(0, 2);
04c943b1 2106
9e1c7236
VZ
2107 size_t posFirstSlash =
2108 fullpath.find_first_of(GetPathTerminators(format));
2109 if ( posFirstSlash != wxString::npos )
2110 {
2111 fullpath[posFirstSlash] = wxFILE_SEP_DSK;
04c943b1 2112
9e1c7236
VZ
2113 // UNC paths are always absolute, right? (FIXME)
2114 fullpath.insert(posFirstSlash + 1, 1, wxFILE_SEP_PATH_DOS);
3c621059
JJ
2115 }
2116 }
04c943b1 2117
a385b5df
RR
2118 // We separate the volume here
2119 if ( format == wxPATH_DOS || format == wxPATH_VMS )
04c943b1 2120 {
a385b5df 2121 wxString sepVol = GetVolumeSeparator(format);
24eb81cb 2122
04c943b1
VZ
2123 size_t posFirstColon = fullpath.find_first_of(sepVol);
2124 if ( posFirstColon != wxString::npos )
2125 {
2126 if ( pstrVolume )
2127 {
2128 *pstrVolume = fullpath.Left(posFirstColon);
2129 }
2130
2131 // remove the volume name and the separator from the full path
2132 fullpath.erase(0, posFirstColon + sepVol.length());
2133 }
2134 }
2135
f1e77933
VZ
2136 if ( pstrPath )
2137 *pstrPath = fullpath;
2138}
2139
2140/* static */
2141void wxFileName::SplitPath(const wxString& fullpathWithVolume,
2142 wxString *pstrVolume,
2143 wxString *pstrPath,
2144 wxString *pstrName,
2145 wxString *pstrExt,
dfecbee5 2146 bool *hasExt,
f1e77933
VZ
2147 wxPathFormat format)
2148{
2149 format = GetFormat(format);
2150
2151 wxString fullpath;
2152 SplitVolume(fullpathWithVolume, pstrVolume, &fullpath, format);
2153
04c943b1
VZ
2154 // find the positions of the last dot and last path separator in the path
2155 size_t posLastDot = fullpath.find_last_of(wxFILE_SEP_EXT);
f1e77933 2156 size_t posLastSlash = fullpath.find_last_of(GetPathTerminators(format));
04c943b1 2157
e5a573a2 2158 // check whether this dot occurs at the very beginning of a path component
04c943b1 2159 if ( (posLastDot != wxString::npos) &&
e5a573a2
VZ
2160 (posLastDot == 0 ||
2161 IsPathSeparator(fullpath[posLastDot - 1]) ||
2162 (format == wxPATH_VMS && fullpath[posLastDot - 1] == _T(']'))) )
f1e77933
VZ
2163 {
2164 // dot may be (and commonly -- at least under Unix -- is) the first
2165 // character of the filename, don't treat the entire filename as
2166 // extension in this case
2167 posLastDot = wxString::npos;
2168 }
9e8d8607 2169
8e7dda21
VZ
2170 // if we do have a dot and a slash, check that the dot is in the name part
2171 if ( (posLastDot != wxString::npos) &&
2172 (posLastSlash != wxString::npos) &&
2173 (posLastDot < posLastSlash) )
9e8d8607
VZ
2174 {
2175 // the dot is part of the path, not the start of the extension
2176 posLastDot = wxString::npos;
2177 }
2178
2179 // now fill in the variables provided by user
2180 if ( pstrPath )
2181 {
2182 if ( posLastSlash == wxString::npos )
2183 {
2184 // no path at all
2185 pstrPath->Empty();
2186 }
2187 else
2188 {
04c943b1 2189 // take everything up to the path separator but take care to make
353f41cb 2190 // the path equal to something like '/', not empty, for the files
04c943b1
VZ
2191 // immediately under root directory
2192 size_t len = posLastSlash;
91b4bd63
SC
2193
2194 // this rule does not apply to mac since we do not start with colons (sep)
2195 // except for relative paths
2196 if ( !len && format != wxPATH_MAC)
04c943b1
VZ
2197 len++;
2198
2199 *pstrPath = fullpath.Left(len);
2200
2201 // special VMS hack: remove the initial bracket
2202 if ( format == wxPATH_VMS )
2203 {
2204 if ( (*pstrPath)[0u] == _T('[') )
2205 pstrPath->erase(0, 1);
2206 }
9e8d8607
VZ
2207 }
2208 }
2209
2210 if ( pstrName )
2211 {
42b1f941
VZ
2212 // take all characters starting from the one after the last slash and
2213 // up to, but excluding, the last dot
9e8d8607 2214 size_t nStart = posLastSlash == wxString::npos ? 0 : posLastSlash + 1;
8e7dda21
VZ
2215 size_t count;
2216 if ( posLastDot == wxString::npos )
2217 {
2218 // take all until the end
2219 count = wxString::npos;
2220 }
2221 else if ( posLastSlash == wxString::npos )
2222 {
2223 count = posLastDot;
2224 }
2225 else // have both dot and slash
2226 {
2227 count = posLastDot - posLastSlash - 1;
2228 }
9e8d8607
VZ
2229
2230 *pstrName = fullpath.Mid(nStart, count);
2231 }
2232
dfecbee5
VZ
2233 // finally deal with the extension here: we have an added complication that
2234 // extension may be empty (but present) as in "foo." where trailing dot
2235 // indicates the empty extension at the end -- and hence we must remember
2236 // that we have it independently of pstrExt
2237 if ( posLastDot == wxString::npos )
9e8d8607 2238 {
dfecbee5
VZ
2239 // no extension
2240 if ( pstrExt )
2241 pstrExt->clear();
2242 if ( hasExt )
2243 *hasExt = false;
2244 }
2245 else
2246 {
2247 // take everything after the dot
2248 if ( pstrExt )
9e8d8607 2249 *pstrExt = fullpath.Mid(posLastDot + 1);
dfecbee5
VZ
2250 if ( hasExt )
2251 *hasExt = true;
9e8d8607
VZ
2252 }
2253}
951cd180 2254
6f91bc33
VZ
2255/* static */
2256void wxFileName::SplitPath(const wxString& fullpath,
2257 wxString *path,
2258 wxString *name,
2259 wxString *ext,
2260 wxPathFormat format)
2261{
2262 wxString volume;
2263 SplitPath(fullpath, &volume, path, name, ext, format);
2264
67c34f64 2265 if ( path )
6f91bc33 2266 {
67c34f64 2267 path->Prepend(wxGetVolumeString(volume, format));
6f91bc33
VZ
2268 }
2269}
2270
951cd180
VZ
2271// ----------------------------------------------------------------------------
2272// time functions
2273// ----------------------------------------------------------------------------
2274
e2b87f38
VZ
2275#if wxUSE_DATETIME
2276
6dbb903b
VZ
2277bool wxFileName::SetTimes(const wxDateTime *dtAccess,
2278 const wxDateTime *dtMod,
2279 const wxDateTime *dtCreate)
951cd180 2280{
2b5f62a0 2281#if defined(__WIN32__)
6bc176b4
VZ
2282 FILETIME ftAccess, ftCreate, ftWrite;
2283
2284 if ( dtCreate )
2285 ConvertWxToFileTime(&ftCreate, *dtCreate);
2286 if ( dtAccess )
2287 ConvertWxToFileTime(&ftAccess, *dtAccess);
2288 if ( dtMod )
2289 ConvertWxToFileTime(&ftWrite, *dtMod);
2290
2291 wxString path;
2292 int flags;
2b5f62a0
VZ
2293 if ( IsDir() )
2294 {
6bc176b4
VZ
2295 if ( wxGetOsVersion() == wxOS_WINDOWS_9X )
2296 {
2297 wxLogError(_("Setting directory access times is not supported "
2298 "under this OS version"));
2299 return false;
2300 }
2301
2302 path = GetPath();
2303 flags = FILE_FLAG_BACKUP_SEMANTICS;
2b5f62a0
VZ
2304 }
2305 else // file
2306 {
6bc176b4
VZ
2307 path = GetFullPath();
2308 flags = 0;
2309 }
2310
2311 wxFileHandle fh(path, wxFileHandle::Write, flags);
2312 if ( fh.IsOk() )
2313 {
2314 if ( ::SetFileTime(fh,
2315 dtCreate ? &ftCreate : NULL,
2316 dtAccess ? &ftAccess : NULL,
2317 dtMod ? &ftWrite : NULL) )
2b5f62a0 2318 {
6bc176b4 2319 return true;
2b5f62a0
VZ
2320 }
2321 }
2322#elif defined(__UNIX_LIKE__) || (defined(__DOS__) && defined(__WATCOMC__))
17a1ebd1
VZ
2323 wxUnusedVar(dtCreate);
2324
246c704f
VZ
2325 if ( !dtAccess && !dtMod )
2326 {
2327 // can't modify the creation time anyhow, don't try
f363e05c 2328 return true;
246c704f
VZ
2329 }
2330
2331 // if dtAccess or dtMod is not specified, use the other one (which must be
2332 // non NULL because of the test above) for both times
951cd180 2333 utimbuf utm;
246c704f
VZ
2334 utm.actime = dtAccess ? dtAccess->GetTicks() : dtMod->GetTicks();
2335 utm.modtime = dtMod ? dtMod->GetTicks() : dtAccess->GetTicks();
401eb3de 2336 if ( utime(GetFullPath().fn_str(), &utm) == 0 )
951cd180 2337 {
f363e05c 2338 return true;
951cd180 2339 }
951cd180 2340#else // other platform
7a893a31
WS
2341 wxUnusedVar(dtAccess);
2342 wxUnusedVar(dtMod);
2343 wxUnusedVar(dtCreate);
951cd180
VZ
2344#endif // platforms
2345
2346 wxLogSysError(_("Failed to modify file times for '%s'"),
2347 GetFullPath().c_str());
2348
f363e05c 2349 return false;
951cd180
VZ
2350}
2351
2352bool wxFileName::Touch()
2353{
2354#if defined(__UNIX_LIKE__)
2355 // under Unix touching file is simple: just pass NULL to utime()
401eb3de 2356 if ( utime(GetFullPath().fn_str(), NULL) == 0 )
951cd180 2357 {
f363e05c 2358 return true;
951cd180
VZ
2359 }
2360
2361 wxLogSysError(_("Failed to touch the file '%s'"), GetFullPath().c_str());
2362
f363e05c 2363 return false;
951cd180
VZ
2364#else // other platform
2365 wxDateTime dtNow = wxDateTime::Now();
2366
6dbb903b 2367 return SetTimes(&dtNow, &dtNow, NULL /* don't change create time */);
951cd180
VZ
2368#endif // platforms
2369}
2370
2371bool wxFileName::GetTimes(wxDateTime *dtAccess,
2372 wxDateTime *dtMod,
6dbb903b 2373 wxDateTime *dtCreate) const
951cd180 2374{
2b5f62a0
VZ
2375#if defined(__WIN32__)
2376 // we must use different methods for the files and directories under
2377 // Windows as CreateFile(GENERIC_READ) doesn't work for the directories and
2378 // CreateFile(FILE_FLAG_BACKUP_SEMANTICS) works -- but only under NT and
2379 // not 9x
2380 bool ok;
2381 FILETIME ftAccess, ftCreate, ftWrite;
9a0c5c01 2382 if ( IsDir() )
2b5f62a0
VZ
2383 {
2384 // implemented in msw/dir.cpp
2385 extern bool wxGetDirectoryTimes(const wxString& dirname,
2386 FILETIME *, FILETIME *, FILETIME *);
2387
2388 // we should pass the path without the trailing separator to
2389 // wxGetDirectoryTimes()
2390 ok = wxGetDirectoryTimes(GetPath(wxPATH_GET_VOLUME),
2391 &ftAccess, &ftCreate, &ftWrite);
2392 }
2393 else // file
2394 {
2395 wxFileHandle fh(GetFullPath(), wxFileHandle::Read);
2396 if ( fh.IsOk() )
2397 {
2398 ok = ::GetFileTime(fh,
2399 dtCreate ? &ftCreate : NULL,
2400 dtAccess ? &ftAccess : NULL,
2401 dtMod ? &ftWrite : NULL) != 0;
2402 }
2403 else
2404 {
f363e05c 2405 ok = false;
2b5f62a0
VZ
2406 }
2407 }
2408
2409 if ( ok )
2410 {
2411 if ( dtCreate )
2412 ConvertFileTimeToWx(dtCreate, ftCreate);
2413 if ( dtAccess )
2414 ConvertFileTimeToWx(dtAccess, ftAccess);
2415 if ( dtMod )
2416 ConvertFileTimeToWx(dtMod, ftWrite);
2417
f363e05c 2418 return true;
2b5f62a0 2419 }
bf58daba 2420#elif defined(__UNIX_LIKE__) || defined(__WXMAC__) || defined(__OS2__) || (defined(__DOS__) && defined(__WATCOMC__))
51cb1a65 2421 // no need to test for IsDir() here
951cd180 2422 wxStructStat stBuf;
92980e90 2423 if ( wxStat( GetFullPath().c_str(), &stBuf) == 0 )
951cd180
VZ
2424 {
2425 if ( dtAccess )
2426 dtAccess->Set(stBuf.st_atime);
2427 if ( dtMod )
2428 dtMod->Set(stBuf.st_mtime);
6dbb903b
VZ
2429 if ( dtCreate )
2430 dtCreate->Set(stBuf.st_ctime);
951cd180 2431
f363e05c 2432 return true;
951cd180 2433 }
951cd180 2434#else // other platform
7a893a31
WS
2435 wxUnusedVar(dtAccess);
2436 wxUnusedVar(dtMod);
2437 wxUnusedVar(dtCreate);
951cd180
VZ
2438#endif // platforms
2439
2440 wxLogSysError(_("Failed to retrieve file times for '%s'"),
2441 GetFullPath().c_str());
2442
f363e05c 2443 return false;
951cd180
VZ
2444}
2445
e2b87f38
VZ
2446#endif // wxUSE_DATETIME
2447
23b8a262
JS
2448
2449// ----------------------------------------------------------------------------
2450// file size functions
2451// ----------------------------------------------------------------------------
2452
bd08f2f7
VZ
2453#if wxUSE_LONGLONG
2454
23b8a262
JS
2455/* static */
2456wxULongLong wxFileName::GetSize(const wxString &filename)
2457{
2458 if (!wxFileExists(filename))
2459 return wxInvalidSize;
2460
cdbce971
WS
2461#if defined(__WXPALMOS__)
2462 // TODO
2463 return wxInvalidSize;
2464#elif defined(__WIN32__)
23b8a262
JS
2465 wxFileHandle f(filename, wxFileHandle::Read);
2466 if (!f.IsOk())
2467 return wxInvalidSize;
2468
2469 DWORD lpFileSizeHigh;
2470 DWORD ret = GetFileSize(f, &lpFileSizeHigh);
5ab9534b 2471 if ( ret == INVALID_FILE_SIZE && ::GetLastError() != NO_ERROR )
23b8a262
JS
2472 return wxInvalidSize;
2473
5ab9534b
VZ
2474 return wxULongLong(lpFileSizeHigh, ret);
2475#else // ! __WIN32__
23b8a262
JS
2476 wxStructStat st;
2477#ifndef wxNEED_WX_UNISTD_H
2478 if (wxStat( filename.fn_str() , &st) != 0)
2479#else
2480 if (wxStat( filename, &st) != 0)
2481#endif
2482 return wxInvalidSize;
2483 return wxULongLong(st.st_size);
2484#endif
2485}
2486
2487/* static */
2488wxString wxFileName::GetHumanReadableSize(const wxULongLong &bs,
2489 const wxString &nullsize,
2490 int precision)
2491{
2492 static const double KILOBYTESIZE = 1024.0;
2493 static const double MEGABYTESIZE = 1024.0*KILOBYTESIZE;
2494 static const double GIGABYTESIZE = 1024.0*MEGABYTESIZE;
2495 static const double TERABYTESIZE = 1024.0*GIGABYTESIZE;
2496
2497 if (bs == 0 || bs == wxInvalidSize)
2498 return nullsize;
2499
2500 double bytesize = bs.ToDouble();
2501 if (bytesize < KILOBYTESIZE)
2502 return wxString::Format(_("%s B"), bs.ToString().c_str());
2503 if (bytesize < MEGABYTESIZE)
2504 return wxString::Format(_("%.*f kB"), precision, bytesize/KILOBYTESIZE);
2505 if (bytesize < GIGABYTESIZE)
2506 return wxString::Format(_("%.*f MB"), precision, bytesize/MEGABYTESIZE);
2507 if (bytesize < TERABYTESIZE)
2508 return wxString::Format(_("%.*f GB"), precision, bytesize/GIGABYTESIZE);
2509
2510 return wxString::Format(_("%.*f TB"), precision, bytesize/TERABYTESIZE);
2511}
2512
2513wxULongLong wxFileName::GetSize() const
2514{
2515 return GetSize(GetFullPath());
2516}
2517
2518wxString wxFileName::GetHumanReadableSize(const wxString &failmsg, int precision) const
2519{
2520 return GetHumanReadableSize(GetSize(), failmsg, precision);
2521}
2522
bd08f2f7 2523#endif // wxUSE_LONGLONG
23b8a262
JS
2524
2525// ----------------------------------------------------------------------------
2526// Mac-specific functions
2527// ----------------------------------------------------------------------------
2528
26eef304 2529#if defined( __WXOSX_MAC__ ) && wxOSX_USE_CARBON
4dfbcdd5 2530
56ce942b
VZ
2531namespace
2532{
2533
0ca4ae93 2534class MacDefaultExtensionRecord
4dfbcdd5 2535{
56ce942b
VZ
2536public:
2537 MacDefaultExtensionRecord()
2538 {
2539 m_type =
2540 m_creator = 0 ;
2541 }
4dfbcdd5 2542
56ce942b 2543 // default copy ctor, assignment operator and dtor are ok
0ca4ae93 2544
56ce942b
VZ
2545 MacDefaultExtensionRecord(const wxString& ext, OSType type, OSType creator)
2546 : m_ext(ext)
2547 {
2548 m_type = type;
2549 m_creator = creator;
2550 }
2551
2552 wxString m_ext;
2553 OSType m_type;
2554 OSType m_creator;
2555};
2556
2557WX_DECLARE_OBJARRAY(MacDefaultExtensionRecord, MacDefaultExtensionArray);
2558
2559bool gMacDefaultExtensionsInited = false;
0ca4ae93 2560
4dfbcdd5 2561#include "wx/arrimpl.cpp"
0ca4ae93 2562
56ce942b 2563WX_DEFINE_EXPORTED_OBJARRAY(MacDefaultExtensionArray);
4dfbcdd5 2564
56ce942b 2565MacDefaultExtensionArray gMacDefaultExtensions;
4dfbcdd5 2566
5974c3cf 2567// load the default extensions
56ce942b 2568const MacDefaultExtensionRecord gDefaults[] =
4dfbcdd5 2569{
56ce942b
VZ
2570 MacDefaultExtensionRecord( "txt", 'TEXT', 'ttxt' ),
2571 MacDefaultExtensionRecord( "tif", 'TIFF', '****' ),
2572 MacDefaultExtensionRecord( "jpg", 'JPEG', '****' ),
2573};
0ea621cc 2574
56ce942b 2575void MacEnsureDefaultExtensionsLoaded()
5974c3cf
SC
2576{
2577 if ( !gMacDefaultExtensionsInited )
4dfbcdd5 2578 {
5974c3cf
SC
2579 // we could load the pc exchange prefs here too
2580 for ( size_t i = 0 ; i < WXSIZEOF( gDefaults ) ; ++i )
2581 {
2582 gMacDefaultExtensions.Add( gDefaults[i] ) ;
2583 }
56ce942b 2584 gMacDefaultExtensionsInited = true;
0ea621cc 2585 }
4dfbcdd5 2586}
a2b77260 2587
56ce942b
VZ
2588} // anonymous namespace
2589
0ea621cc 2590bool wxFileName::MacSetTypeAndCreator( wxUint32 type , wxUint32 creator )
4dfbcdd5 2591{
a2b77260
SC
2592 FSRef fsRef ;
2593 FSCatalogInfo catInfo;
2594 FileInfo *finfo ;
4dfbcdd5 2595
a2b77260
SC
2596 if ( wxMacPathToFSRef( GetFullPath() , &fsRef ) == noErr )
2597 {
a62848fd
WS
2598 if ( FSGetCatalogInfo (&fsRef, kFSCatInfoFinderInfo, &catInfo, NULL, NULL, NULL) == noErr )
2599 {
2600 finfo = (FileInfo*)&catInfo.finderInfo;
2601 finfo->fileType = type ;
2602 finfo->fileCreator = creator ;
2603 FSSetCatalogInfo( &fsRef, kFSCatInfoFinderInfo, &catInfo ) ;
a2b77260 2604 return true ;
a62848fd 2605 }
a2b77260
SC
2606 }
2607 return false ;
4dfbcdd5
SC
2608}
2609
0ea621cc 2610bool wxFileName::MacGetTypeAndCreator( wxUint32 *type , wxUint32 *creator )
4dfbcdd5 2611{
a2b77260
SC
2612 FSRef fsRef ;
2613 FSCatalogInfo catInfo;
2614 FileInfo *finfo ;
4dfbcdd5 2615
a2b77260
SC
2616 if ( wxMacPathToFSRef( GetFullPath() , &fsRef ) == noErr )
2617 {
a62848fd
WS
2618 if ( FSGetCatalogInfo (&fsRef, kFSCatInfoFinderInfo, &catInfo, NULL, NULL, NULL) == noErr )
2619 {
2620 finfo = (FileInfo*)&catInfo.finderInfo;
2621 *type = finfo->fileType ;
2622 *creator = finfo->fileCreator ;
a2b77260 2623 return true ;
a62848fd 2624 }
a2b77260
SC
2625 }
2626 return false ;
4dfbcdd5
SC
2627}
2628
2629bool wxFileName::MacSetDefaultTypeAndCreator()
2630{
2631 wxUint32 type , creator ;
2632 if ( wxFileName::MacFindDefaultTypeAndCreator(GetExt() , &type ,
2633 &creator ) )
2634 {
f63fb56d
GD
2635 return MacSetTypeAndCreator( type , creator ) ;
2636 }
2637 return false;
4dfbcdd5
SC
2638}
2639
0ea621cc 2640bool wxFileName::MacFindDefaultTypeAndCreator( const wxString& ext , wxUint32 *type , wxUint32 *creator )
4dfbcdd5
SC
2641{
2642 MacEnsureDefaultExtensionsLoaded() ;
2643 wxString extl = ext.Lower() ;
2644 for( int i = gMacDefaultExtensions.Count() - 1 ; i >= 0 ; --i )
2645 {
2646 if ( gMacDefaultExtensions.Item(i).m_ext == extl )
2647 {
2648 *type = gMacDefaultExtensions.Item(i).m_type ;
2649 *creator = gMacDefaultExtensions.Item(i).m_creator ;
2650 return true ;
2651 }
2652 }
2653 return false ;
2654}
2655
2656void wxFileName::MacRegisterDefaultTypeAndCreator( const wxString& ext , wxUint32 type , wxUint32 creator )
2657{
56ce942b
VZ
2658 MacEnsureDefaultExtensionsLoaded();
2659 MacDefaultExtensionRecord rec(ext.Lower(), type, creator);
2660 gMacDefaultExtensions.Add( rec );
4dfbcdd5 2661}
56ce942b
VZ
2662
2663#endif // defined( __WXOSX_MAC__ ) && wxOSX_USE_CARBON