1
/////////////////////////////////////////////////////////////////////////////
2
// Name: src/common/filename.cpp
3
// Purpose: wxFileName - encapsulates a file path
4
// Author: Robert Roebling, Vadim Zeitlin
7
// RCS-ID: $Id: filename.cpp,v 1.158.2.6 2006/03/02 12:46:06 JS Exp $
8
// Copyright: (c) 2000 Robert Roebling
9
// Licence: wxWindows licence
10
/////////////////////////////////////////////////////////////////////////////
13
Here are brief descriptions of the filename formats supported by this class:
15
wxPATH_UNIX: standard Unix format, used under Darwin as well, absolute file
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
21
wxPATH_DOS: DOS/Windows format, absolute file names have the form:
22
drive:\dir1\dir2\...\dirN\filename.ext where drive is a single
23
letter. "." and ".." as for Unix but no "~".
25
There are also UNC names of the form \\share\fullpath
27
wxPATH_MAC: Mac OS 8/9 and Mac OS X under CodeWarrior 7 format, absolute file
29
volume:dir1:...:dirN:filename
30
and the relative file names are either
31
:dir1:...:dirN:filename
34
(although :filename works as well).
35
Since the volume is just part of the file path, it is not
36
treated like a separate entity as it is done under DOS and
37
VMS, it is just treated as another dir.
39
wxPATH_VMS: VMS native format, absolute file names have the form
40
<device>:[dir1.dir2.dir3]file.txt
42
<device>:[000000.dir1.dir2.dir3]file.txt
44
the <device> is the physical device (i.e. disk). 000000 is the
45
root directory on the device which can be omitted.
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.
50
[ start of directory specification
51
. separator between directory and subdirectory
52
] between directory and file
55
// ============================================================================
57
// ============================================================================
59
// ----------------------------------------------------------------------------
61
// ----------------------------------------------------------------------------
63
#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
64
#pragma implementation "filename.h"
67
// For compilers that support precompilation, includes "wx.h".
68
#include "wx/wxprec.h"
80
#include "wx/filename.h"
81
#include "wx/tokenzr.h"
82
#include "wx/config.h" // for wxExpandEnvVars
85
#include "wx/dynlib.h"
87
// For GetShort/LongPathName
89
#include "wx/msw/wrapwin.h"
90
#if defined(__MINGW32__)
91
#include "wx/msw/gccpriv.h"
96
#include "wx/msw/private.h"
99
#if defined(__WXMAC__)
100
#include "wx/mac/private.h" // includes mac headers
103
// utime() is POSIX so should normally be available on all Unices
105
#include <sys/types.h>
107
#include <sys/stat.h>
117
#include <sys/types.h>
119
#include <sys/stat.h>
130
#include <sys/utime.h>
131
#include <sys/stat.h>
142
#define MAX_PATH _MAX_PATH
145
// ----------------------------------------------------------------------------
147
// ----------------------------------------------------------------------------
149
// small helper class which opens and closes the file - we use it just to get
150
// a file handle for the given file name to pass it to some Win32 API function
151
#if defined(__WIN32__) && !defined(__WXMICROWIN__)
162
wxFileHandle(const wxString& filename, OpenMode mode)
164
m_hFile = ::CreateFile
167
mode == Read ? GENERIC_READ // access mask
169
FILE_SHARE_READ | // sharing mode
170
FILE_SHARE_WRITE, // (allow everything)
171
NULL, // no secutity attr
172
OPEN_EXISTING, // creation disposition
174
NULL // no template file
177
if ( m_hFile == INVALID_HANDLE_VALUE )
179
wxLogSysError(_("Failed to open '%s' for %s"),
181
mode == Read ? _("reading") : _("writing"));
187
if ( m_hFile != INVALID_HANDLE_VALUE )
189
if ( !::CloseHandle(m_hFile) )
191
wxLogSysError(_("Failed to close file handle"));
196
// return true only if the file could be opened successfully
197
bool IsOk() const { return m_hFile != INVALID_HANDLE_VALUE; }
200
operator HANDLE() const { return m_hFile; }
208
// ----------------------------------------------------------------------------
210
// ----------------------------------------------------------------------------
212
#if wxUSE_DATETIME && defined(__WIN32__) && !defined(__WXMICROWIN__)
214
// convert between wxDateTime and FILETIME which is a 64-bit value representing
215
// the number of 100-nanosecond intervals since January 1, 1601.
217
static void ConvertFileTimeToWx(wxDateTime *dt, const FILETIME &ft)
219
FILETIME ftcopy = ft;
221
if ( !::FileTimeToLocalFileTime(&ftcopy, &ftLocal) )
223
wxLogLastError(_T("FileTimeToLocalFileTime"));
227
if ( !::FileTimeToSystemTime(&ftLocal, &st) )
229
wxLogLastError(_T("FileTimeToSystemTime"));
232
dt->Set(st.wDay, wxDateTime::Month(st.wMonth - 1), st.wYear,
233
st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
236
static void ConvertWxToFileTime(FILETIME *ft, const wxDateTime& dt)
239
st.wDay = dt.GetDay();
240
st.wMonth = (WORD)(dt.GetMonth() + 1);
241
st.wYear = (WORD)dt.GetYear();
242
st.wHour = dt.GetHour();
243
st.wMinute = dt.GetMinute();
244
st.wSecond = dt.GetSecond();
245
st.wMilliseconds = dt.GetMillisecond();
248
if ( !::SystemTimeToFileTime(&st, &ftLocal) )
250
wxLogLastError(_T("SystemTimeToFileTime"));
253
if ( !::LocalFileTimeToFileTime(&ftLocal, ft) )
255
wxLogLastError(_T("LocalFileTimeToFileTime"));
259
#endif // wxUSE_DATETIME && __WIN32__
261
// return a string with the volume par
262
static wxString wxGetVolumeString(const wxString& volume, wxPathFormat format)
266
if ( !volume.empty() )
268
format = wxFileName::GetFormat(format);
270
// Special Windows UNC paths hack, part 2: undo what we did in
271
// SplitPath() and make an UNC path if we have a drive which is not a
272
// single letter (hopefully the network shares can't be one letter only
273
// although I didn't find any authoritative docs on this)
274
if ( format == wxPATH_DOS && volume.length() > 1 )
276
path << wxFILE_SEP_PATH_DOS << wxFILE_SEP_PATH_DOS << volume;
278
else if ( format == wxPATH_DOS || format == wxPATH_VMS )
280
path << volume << wxFileName::GetVolumeSeparator(format);
288
// ============================================================================
290
// ============================================================================
292
// ----------------------------------------------------------------------------
293
// wxFileName construction
294
// ----------------------------------------------------------------------------
296
void wxFileName::Assign( const wxFileName &filepath )
298
m_volume = filepath.GetVolume();
299
m_dirs = filepath.GetDirs();
300
m_name = filepath.GetName();
301
m_ext = filepath.GetExt();
302
m_relative = filepath.m_relative;
303
m_hasExt = filepath.m_hasExt;
306
void wxFileName::Assign(const wxString& volume,
307
const wxString& path,
308
const wxString& name,
311
wxPathFormat format )
313
SetPath( path, format );
322
void wxFileName::SetPath( const wxString& pathOrig, wxPathFormat format )
326
if ( pathOrig.empty() )
334
format = GetFormat( format );
336
// 0) deal with possible volume part first
339
SplitVolume(pathOrig, &volume, &path, format);
340
if ( !volume.empty() )
347
// 1) Determine if the path is relative or absolute.
348
wxChar leadingChar = path[0u];
353
m_relative = leadingChar == wxT(':');
355
// We then remove a leading ":". The reason is in our
356
// storage form for relative paths:
357
// ":dir:file.txt" actually means "./dir/file.txt" in
358
// DOS notation and should get stored as
359
// (relative) (dir) (file.txt)
360
// "::dir:file.txt" actually means "../dir/file.txt"
361
// stored as (relative) (..) (dir) (file.txt)
362
// This is important only for the Mac as an empty dir
363
// actually means <UP>, whereas under DOS, double
364
// slashes can be ignored: "\\\\" is the same as "\\".
370
// TODO: what is the relative path format here?
375
wxFAIL_MSG( _T("Unknown path format") );
376
// !! Fall through !!
379
// the paths of the form "~" or "~username" are absolute
380
m_relative = leadingChar != wxT('/') && leadingChar != _T('~');
384
m_relative = !IsPathSeparator(leadingChar, format);
389
// 2) Break up the path into its members. If the original path
390
// was just "/" or "\\", m_dirs will be empty. We know from
391
// the m_relative field, if this means "nothing" or "root dir".
393
wxStringTokenizer tn( path, GetPathSeparators(format) );
395
while ( tn.HasMoreTokens() )
397
wxString token = tn.GetNextToken();
399
// Remove empty token under DOS and Unix, interpret them
403
if (format == wxPATH_MAC)
404
m_dirs.Add( wxT("..") );
414
void wxFileName::Assign(const wxString& fullpath,
417
wxString volume, path, name, ext;
419
SplitPath(fullpath, &volume, &path, &name, &ext, &hasExt, format);
421
Assign(volume, path, name, ext, hasExt, format);
424
void wxFileName::Assign(const wxString& fullpathOrig,
425
const wxString& fullname,
428
// always recognize fullpath as directory, even if it doesn't end with a
430
wxString fullpath = fullpathOrig;
431
if ( !wxEndsWithPathSeparator(fullpath) )
433
fullpath += GetPathSeparator(format);
436
wxString volume, path, name, ext;
439
// do some consistency checks in debug mode: the name should be really just
440
// the filename and the path should be really just a path
442
wxString volDummy, pathDummy, nameDummy, extDummy;
444
SplitPath(fullname, &volDummy, &pathDummy, &name, &ext, &hasExt, format);
446
wxASSERT_MSG( volDummy.empty() && pathDummy.empty(),
447
_T("the file name shouldn't contain the path") );
449
SplitPath(fullpath, &volume, &path, &nameDummy, &extDummy, format);
451
wxASSERT_MSG( nameDummy.empty() && extDummy.empty(),
452
_T("the path shouldn't contain file name nor extension") );
454
#else // !__WXDEBUG__
455
SplitPath(fullname, NULL /* no volume */, NULL /* no path */,
456
&name, &ext, &hasExt, format);
457
SplitPath(fullpath, &volume, &path, NULL, NULL, format);
458
#endif // __WXDEBUG__/!__WXDEBUG__
460
Assign(volume, path, name, ext, hasExt, format);
463
void wxFileName::Assign(const wxString& pathOrig,
464
const wxString& name,
470
SplitVolume(pathOrig, &volume, &path, format);
472
Assign(volume, path, name, ext, format);
475
void wxFileName::AssignDir(const wxString& dir, wxPathFormat format)
477
Assign(dir, wxEmptyString, format);
480
void wxFileName::Clear()
486
m_ext = wxEmptyString;
488
// we don't have any absolute path for now
496
wxFileName wxFileName::FileName(const wxString& file, wxPathFormat format)
498
return wxFileName(file, format);
502
wxFileName wxFileName::DirName(const wxString& dir, wxPathFormat format)
505
fn.AssignDir(dir, format);
509
// ----------------------------------------------------------------------------
511
// ----------------------------------------------------------------------------
513
bool wxFileName::FileExists() const
515
return wxFileName::FileExists( GetFullPath() );
518
bool wxFileName::FileExists( const wxString &file )
520
return ::wxFileExists( file );
523
bool wxFileName::DirExists() const
525
return wxFileName::DirExists( GetFullPath() );
528
bool wxFileName::DirExists( const wxString &dir )
530
return ::wxDirExists( dir );
533
// ----------------------------------------------------------------------------
534
// CWD and HOME stuff
535
// ----------------------------------------------------------------------------
537
void wxFileName::AssignCwd(const wxString& volume)
539
AssignDir(wxFileName::GetCwd(volume));
543
wxString wxFileName::GetCwd(const wxString& volume)
545
// if we have the volume, we must get the current directory on this drive
546
// and to do this we have to chdir to this volume - at least under Windows,
547
// I don't know how to get the current drive on another volume elsewhere
550
if ( !volume.empty() )
553
SetCwd(volume + GetVolumeSeparator());
556
wxString cwd = ::wxGetCwd();
558
if ( !volume.empty() )
566
bool wxFileName::SetCwd()
568
return wxFileName::SetCwd( GetFullPath() );
571
bool wxFileName::SetCwd( const wxString &cwd )
573
return ::wxSetWorkingDirectory( cwd );
576
void wxFileName::AssignHomeDir()
578
AssignDir(wxFileName::GetHomeDir());
581
wxString wxFileName::GetHomeDir()
583
return ::wxGetHomeDir();
588
void wxFileName::AssignTempFileName(const wxString& prefix, wxFile *fileTemp)
590
wxString tempname = CreateTempFileName(prefix, fileTemp);
591
if ( tempname.empty() )
593
// error, failed to get temp file name
604
wxFileName::CreateTempFileName(const wxString& prefix, wxFile *fileTemp)
606
wxString path, dir, name;
608
// use the directory specified by the prefix
609
SplitPath(prefix, &dir, &name, NULL /* extension */);
613
dir = wxGetenv(_T("TMPDIR"));
616
dir = wxGetenv(_T("TMP"));
619
dir = wxGetenv(_T("TEMP"));
624
#if defined(__WXWINCE__)
627
// FIXME. Create \temp dir?
628
if (DirExists(wxT("\\temp")))
631
path = dir + wxT("\\") + name;
633
while (FileExists(path))
635
path = dir + wxT("\\") + name ;
640
#elif defined(__WINDOWS__) && !defined(__WXMICROWIN__)
644
if ( !::GetTempPath(MAX_PATH, wxStringBuffer(dir, MAX_PATH + 1)) )
646
wxLogLastError(_T("GetTempPath"));
651
// GetTempFileName() fails if we pass it an empty string
655
else // we have a dir to create the file in
657
// ensure we use only the back slashes as GetTempFileName(), unlike all
658
// the other APIs, is picky and doesn't accept the forward ones
659
dir.Replace(_T("/"), _T("\\"));
662
if ( !::GetTempFileName(dir, name, 0, wxStringBuffer(path, MAX_PATH + 1)) )
664
wxLogLastError(_T("GetTempFileName"));
673
#if defined(__DOS__) || defined(__OS2__)
675
#elif defined(__WXMAC__)
676
dir = wxMacFindFolder(short(kOnSystemDisk), kTemporaryFolderType, kCreateFolder);
684
if ( !wxEndsWithPathSeparator(dir) &&
685
(name.empty() || !wxIsPathSeparator(name[0u])) )
687
path += wxFILE_SEP_PATH;
692
#if defined(HAVE_MKSTEMP)
693
// scratch space for mkstemp()
694
path += _T("XXXXXX");
696
// we need to copy the path to the buffer in which mkstemp() can modify it
697
wxCharBuffer buf( wxConvFile.cWX2MB( path ) );
699
// cast is safe because the string length doesn't change
700
int fdTemp = mkstemp( (char*)(const char*) buf );
703
// this might be not necessary as mkstemp() on most systems should have
704
// already done it but it doesn't hurt neither...
707
else // mkstemp() succeeded
709
path = wxConvFile.cMB2WX( (const char*) buf );
711
// avoid leaking the fd
714
fileTemp->Attach(fdTemp);
721
#else // !HAVE_MKSTEMP
725
path += _T("XXXXXX");
727
wxCharBuffer buf = wxConvFile.cWX2MB( path );
728
if ( !mktemp( (const char*) buf ) )
734
path = wxConvFile.cMB2WX( (const char*) buf );
736
#else // !HAVE_MKTEMP (includes __DOS__)
737
// generate the unique file name ourselves
738
#if !defined(__DOS__) && !defined(__PALMOS__) && (!defined(__MWERKS__) || defined(__DARWIN__) )
739
path << (unsigned int)getpid();
744
static const size_t numTries = 1000;
745
for ( size_t n = 0; n < numTries; n++ )
747
// 3 hex digits is enough for numTries == 1000 < 4096
748
pathTry = path + wxString::Format(_T("%.03x"), (unsigned int) n);
749
if ( !FileExists(pathTry) )
758
#endif // HAVE_MKTEMP/!HAVE_MKTEMP
760
#endif // HAVE_MKSTEMP/!HAVE_MKSTEMP
762
#endif // Windows/!Windows
766
wxLogSysError(_("Failed to create a temporary file name"));
768
else if ( fileTemp && !fileTemp->IsOpened() )
770
// open the file - of course, there is a race condition here, this is
771
// why we always prefer using mkstemp()...
773
// NB: GetTempFileName() under Windows creates the file, so using
774
// write_excl there would fail
775
if ( !fileTemp->Open(path,
776
#if defined(__WINDOWS__) && !defined(__WXMICROWIN__)
781
wxS_IRUSR | wxS_IWUSR) )
783
// FIXME: If !ok here should we loop and try again with another
784
// file name? That is the standard recourse if open(O_EXCL)
785
// fails, though of course it should be protected against
786
// possible infinite looping too.
788
wxLogError(_("Failed to open temporary file."));
799
// ----------------------------------------------------------------------------
800
// directory operations
801
// ----------------------------------------------------------------------------
803
bool wxFileName::Mkdir( int perm, int flags )
805
return wxFileName::Mkdir( GetFullPath(), perm, flags );
808
bool wxFileName::Mkdir( const wxString& dir, int perm, int flags )
810
if ( flags & wxPATH_MKDIR_FULL )
812
// split the path in components
814
filename.AssignDir(dir);
817
if ( filename.HasVolume())
819
currPath << wxGetVolumeString(filename.GetVolume(), wxPATH_NATIVE);
822
wxArrayString dirs = filename.GetDirs();
823
size_t count = dirs.GetCount();
824
for ( size_t i = 0; i < count; i++ )
827
#if defined(__WXMAC__) && !defined(__DARWIN__)
828
// relative pathnames are exactely the other way round under mac...
829
!filename.IsAbsolute()
831
filename.IsAbsolute()
834
currPath += wxFILE_SEP_PATH;
837
if (!DirExists(currPath))
839
if (!wxMkdir(currPath, perm))
841
// no need to try creating further directories
851
return ::wxMkdir( dir, perm );
854
bool wxFileName::Rmdir()
856
return wxFileName::Rmdir( GetFullPath() );
859
bool wxFileName::Rmdir( const wxString &dir )
861
return ::wxRmdir( dir );
864
// ----------------------------------------------------------------------------
865
// path normalization
866
// ----------------------------------------------------------------------------
868
bool wxFileName::Normalize(int flags,
872
// deal with env vars renaming first as this may seriously change the path
873
if ( flags & wxPATH_NORM_ENV_VARS )
875
wxString pathOrig = GetFullPath(format);
876
wxString path = wxExpandEnvVars(pathOrig);
877
if ( path != pathOrig )
884
// the existing path components
885
wxArrayString dirs = GetDirs();
887
// the path to prepend in front to make the path absolute
890
format = GetFormat(format);
892
// make the path absolute
893
if ( (flags & wxPATH_NORM_ABSOLUTE) && !IsAbsolute(format) )
897
curDir.AssignCwd(GetVolume());
901
curDir.AssignDir(cwd);
904
// the path may be not absolute because it doesn't have the volume name
905
// but in this case we shouldn't modify the directory components of it
906
// but just set the current volume
907
if ( !HasVolume() && curDir.HasVolume() )
909
SetVolume(curDir.GetVolume());
913
// yes, it was the case - we don't need curDir then
919
// handle ~ stuff under Unix only
920
if ( (format == wxPATH_UNIX) && (flags & wxPATH_NORM_TILDE) )
922
if ( !dirs.IsEmpty() )
924
wxString dir = dirs[0u];
925
if ( !dir.empty() && dir[0u] == _T('~') )
927
curDir.AssignDir(wxGetUserHome(dir.c_str() + 1));
934
// transform relative path into abs one
937
wxArrayString dirsNew = curDir.GetDirs();
938
size_t count = dirs.GetCount();
939
for ( size_t n = 0; n < count; n++ )
941
dirsNew.Add(dirs[n]);
947
// now deal with ".", ".." and the rest
949
size_t count = dirs.GetCount();
950
for ( size_t n = 0; n < count; n++ )
952
wxString dir = dirs[n];
954
if ( flags & wxPATH_NORM_DOTS )
956
if ( dir == wxT(".") )
962
if ( dir == wxT("..") )
964
if ( m_dirs.IsEmpty() )
966
wxLogError(_("The path '%s' contains too many \"..\"!"),
967
GetFullPath().c_str());
971
m_dirs.RemoveAt(m_dirs.GetCount() - 1);
976
if ( (flags & wxPATH_NORM_CASE) && !IsCaseSensitive(format) )
984
#if defined(__WIN32__) && !defined(__WXWINCE__) && wxUSE_OLE
985
if ( (flags & wxPATH_NORM_SHORTCUT) )
988
if (GetShortcutTarget(GetFullPath(format), filename))
990
// Repeat this since we may now have a new path
991
if ( (flags & wxPATH_NORM_CASE) && !IsCaseSensitive(format) )
993
filename.MakeLower();
1001
if ( (flags & wxPATH_NORM_CASE) && !IsCaseSensitive(format) )
1003
// VZ: expand env vars here too?
1005
m_volume.MakeLower();
1010
// we do have the path now
1012
// NB: need to do this before (maybe) calling Assign() below
1015
#if defined(__WIN32__)
1016
if ( (flags & wxPATH_NORM_LONG) && (format == wxPATH_DOS) )
1018
Assign(GetLongPath());
1025
// ----------------------------------------------------------------------------
1026
// get the shortcut target
1027
// ----------------------------------------------------------------------------
1029
// WinCE (3) doesn't have CLSID_ShellLink, IID_IShellLink definitions.
1030
// The .lnk file is a plain text file so it should be easy to
1031
// make it work. Hint from Google Groups:
1032
// "If you open up a lnk file, you'll see a
1033
// number, followed by a pound sign (#), followed by more text. The
1034
// number is the number of characters that follows the pound sign. The
1035
// characters after the pound sign are the command line (which _can_
1036
// include arguments) to be executed. Any path (e.g. \windows\program
1037
// files\myapp.exe) that includes spaces needs to be enclosed in
1038
// quotation marks."
1040
#if defined(__WIN32__) && !defined(__WXWINCE__) && wxUSE_OLE
1041
// The following lines are necessary under WinCE
1042
// #include "wx/msw/private.h"
1043
// #include <ole2.h>
1045
#if defined(__WXWINCE__)
1046
#include <shlguid.h>
1049
bool wxFileName::GetShortcutTarget(const wxString& shortcutPath, wxString& targetFilename, wxString* arguments)
1051
wxString path, file, ext;
1052
wxSplitPath(shortcutPath, & path, & file, & ext);
1056
bool success = false;
1058
// Assume it's not a shortcut if it doesn't end with lnk
1059
if (ext.CmpNoCase(wxT("lnk"))!=0)
1062
// create a ShellLink object
1063
hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
1064
IID_IShellLink, (LPVOID*) &psl);
1066
if (SUCCEEDED(hres))
1069
hres = psl->QueryInterface( IID_IPersistFile, (LPVOID *) &ppf);
1070
if (SUCCEEDED(hres))
1072
WCHAR wsz[MAX_PATH];
1074
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, shortcutPath.mb_str(), -1, wsz,
1077
hres = ppf->Load(wsz, 0);
1078
if (SUCCEEDED(hres))
1081
// Wrong prototype in early versions
1082
#if defined(__MINGW32__) && !wxCHECK_W32API_VERSION(2, 2)
1083
psl->GetPath((CHAR*) buf, 2048, NULL, SLGP_UNCPRIORITY);
1085
psl->GetPath(buf, 2048, NULL, SLGP_UNCPRIORITY);
1087
targetFilename = wxString(buf);
1088
success = (shortcutPath != targetFilename);
1090
psl->GetArguments(buf, 2048);
1092
if (!args.empty() && arguments)
1105
// ----------------------------------------------------------------------------
1106
// absolute/relative paths
1107
// ----------------------------------------------------------------------------
1109
bool wxFileName::IsAbsolute(wxPathFormat format) const
1111
// if our path doesn't start with a path separator, it's not an absolute
1116
if ( !GetVolumeSeparator(format).empty() )
1118
// this format has volumes and an absolute path must have one, it's not
1119
// enough to have the full path to bean absolute file under Windows
1120
if ( GetVolume().empty() )
1127
bool wxFileName::MakeRelativeTo(const wxString& pathBase, wxPathFormat format)
1129
wxFileName fnBase = wxFileName::DirName(pathBase, format);
1131
// get cwd only once - small time saving
1132
wxString cwd = wxGetCwd();
1133
Normalize(wxPATH_NORM_ALL & ~wxPATH_NORM_CASE, cwd, format);
1134
fnBase.Normalize(wxPATH_NORM_ALL & ~wxPATH_NORM_CASE, cwd, format);
1136
bool withCase = IsCaseSensitive(format);
1138
// we can't do anything if the files live on different volumes
1139
if ( !GetVolume().IsSameAs(fnBase.GetVolume(), withCase) )
1145
// same drive, so we don't need our volume
1148
// remove common directories starting at the top
1149
while ( !m_dirs.IsEmpty() && !fnBase.m_dirs.IsEmpty() &&
1150
m_dirs[0u].IsSameAs(fnBase.m_dirs[0u], withCase) )
1153
fnBase.m_dirs.RemoveAt(0);
1156
// add as many ".." as needed
1157
size_t count = fnBase.m_dirs.GetCount();
1158
for ( size_t i = 0; i < count; i++ )
1160
m_dirs.Insert(wxT(".."), 0u);
1163
if ( format == wxPATH_UNIX || format == wxPATH_DOS )
1165
// a directory made relative with respect to itself is '.' under Unix
1166
// and DOS, by definition (but we don't have to insert "./" for the
1168
if ( m_dirs.IsEmpty() && IsDir() )
1170
m_dirs.Add(_T('.'));
1180
// ----------------------------------------------------------------------------
1181
// filename kind tests
1182
// ----------------------------------------------------------------------------
1184
bool wxFileName::SameAs(const wxFileName& filepath, wxPathFormat format) const
1186
wxFileName fn1 = *this,
1189
// get cwd only once - small time saving
1190
wxString cwd = wxGetCwd();
1191
fn1.Normalize(wxPATH_NORM_ALL | wxPATH_NORM_CASE, cwd, format);
1192
fn2.Normalize(wxPATH_NORM_ALL | wxPATH_NORM_CASE, cwd, format);
1194
if ( fn1.GetFullPath() == fn2.GetFullPath() )
1197
// TODO: compare inodes for Unix, this works even when filenames are
1198
// different but files are the same (symlinks) (VZ)
1204
bool wxFileName::IsCaseSensitive( wxPathFormat format )
1206
// only Unix filenames are truely case-sensitive
1207
return GetFormat(format) == wxPATH_UNIX;
1211
wxString wxFileName::GetForbiddenChars(wxPathFormat format)
1213
// Inits to forbidden characters that are common to (almost) all platforms.
1214
wxString strForbiddenChars = wxT("*?");
1216
// If asserts, wxPathFormat has been changed. In case of a new path format
1217
// addition, the following code might have to be updated.
1218
wxCOMPILE_TIME_ASSERT(wxPATH_MAX == 5, wxPathFormatChanged);
1219
switch ( GetFormat(format) )
1222
wxFAIL_MSG( wxT("Unknown path format") );
1223
// !! Fall through !!
1229
// On a Mac even names with * and ? are allowed (Tested with OS
1230
// 9.2.1 and OS X 10.2.5)
1231
strForbiddenChars = wxEmptyString;
1235
strForbiddenChars += wxT("\\/:\"<>|");
1242
return strForbiddenChars;
1246
wxString wxFileName::GetVolumeSeparator(wxPathFormat WXUNUSED_IN_WINCE(format))
1249
return wxEmptyString;
1253
if ( (GetFormat(format) == wxPATH_DOS) ||
1254
(GetFormat(format) == wxPATH_VMS) )
1256
sepVol = wxFILE_SEP_DSK;
1265
wxString wxFileName::GetPathSeparators(wxPathFormat format)
1268
switch ( GetFormat(format) )
1271
// accept both as native APIs do but put the native one first as
1272
// this is the one we use in GetFullPath()
1273
seps << wxFILE_SEP_PATH_DOS << wxFILE_SEP_PATH_UNIX;
1277
wxFAIL_MSG( _T("Unknown wxPATH_XXX style") );
1281
seps = wxFILE_SEP_PATH_UNIX;
1285
seps = wxFILE_SEP_PATH_MAC;
1289
seps = wxFILE_SEP_PATH_VMS;
1297
wxString wxFileName::GetPathTerminators(wxPathFormat format)
1299
format = GetFormat(format);
1301
// under VMS the end of the path is ']', not the path separator used to
1302
// separate the components
1303
return format == wxPATH_VMS ? wxString(_T(']')) : GetPathSeparators(format);
1307
bool wxFileName::IsPathSeparator(wxChar ch, wxPathFormat format)
1309
// wxString::Find() doesn't work as expected with NUL - it will always find
1310
// it, so test for it separately
1311
return ch != _T('\0') && GetPathSeparators(format).Find(ch) != wxNOT_FOUND;
1314
// ----------------------------------------------------------------------------
1315
// path components manipulation
1316
// ----------------------------------------------------------------------------
1318
/* static */ bool wxFileName::IsValidDirComponent(const wxString& dir)
1322
wxFAIL_MSG( _T("empty directory passed to wxFileName::InsertDir()") );
1327
const size_t len = dir.length();
1328
for ( size_t n = 0; n < len; n++ )
1330
if ( dir[n] == GetVolumeSeparator() || IsPathSeparator(dir[n]) )
1332
wxFAIL_MSG( _T("invalid directory component in wxFileName") );
1341
void wxFileName::AppendDir( const wxString& dir )
1343
if ( IsValidDirComponent(dir) )
1347
void wxFileName::PrependDir( const wxString& dir )
1352
void wxFileName::InsertDir(size_t before, const wxString& dir)
1354
if ( IsValidDirComponent(dir) )
1355
m_dirs.Insert(dir, before);
1358
void wxFileName::RemoveDir(size_t pos)
1360
m_dirs.RemoveAt(pos);
1363
// ----------------------------------------------------------------------------
1365
// ----------------------------------------------------------------------------
1367
void wxFileName::SetFullName(const wxString& fullname)
1369
SplitPath(fullname, NULL /* no volume */, NULL /* no path */,
1370
&m_name, &m_ext, &m_hasExt);
1373
wxString wxFileName::GetFullName() const
1375
wxString fullname = m_name;
1378
fullname << wxFILE_SEP_EXT << m_ext;
1384
wxString wxFileName::GetPath( int flags, wxPathFormat format ) const
1386
format = GetFormat( format );
1390
// return the volume with the path as well if requested
1391
if ( flags & wxPATH_GET_VOLUME )
1393
fullpath += wxGetVolumeString(GetVolume(), format);
1396
// the leading character
1401
fullpath += wxFILE_SEP_PATH_MAC;
1406
fullpath += wxFILE_SEP_PATH_DOS;
1410
wxFAIL_MSG( wxT("Unknown path format") );
1416
// normally the absolute file names start with a slash
1417
// with one exception: the ones like "~/foo.bar" don't
1419
if ( m_dirs.IsEmpty() || m_dirs[0u] != _T('~') )
1421
fullpath += wxFILE_SEP_PATH_UNIX;
1427
// no leading character here but use this place to unset
1428
// wxPATH_GET_SEPARATOR flag: under VMS it doesn't make sense
1429
// as, if I understand correctly, there should never be a dot
1430
// before the closing bracket
1431
flags &= ~wxPATH_GET_SEPARATOR;
1434
if ( m_dirs.empty() )
1436
// there is nothing more
1440
// then concatenate all the path components using the path separator
1441
if ( format == wxPATH_VMS )
1443
fullpath += wxT('[');
1446
const size_t dirCount = m_dirs.GetCount();
1447
for ( size_t i = 0; i < dirCount; i++ )
1452
if ( m_dirs[i] == wxT(".") )
1454
// skip appending ':', this shouldn't be done in this
1455
// case as "::" is interpreted as ".." under Unix
1459
// convert back from ".." to nothing
1460
if ( !m_dirs[i].IsSameAs(wxT("..")) )
1461
fullpath += m_dirs[i];
1465
wxFAIL_MSG( wxT("Unexpected path format") );
1466
// still fall through
1470
fullpath += m_dirs[i];
1474
// TODO: What to do with ".." under VMS
1476
// convert back from ".." to nothing
1477
if ( !m_dirs[i].IsSameAs(wxT("..")) )
1478
fullpath += m_dirs[i];
1482
if ( (flags & wxPATH_GET_SEPARATOR) || (i != dirCount - 1) )
1483
fullpath += GetPathSeparator(format);
1486
if ( format == wxPATH_VMS )
1488
fullpath += wxT(']');
1494
wxString wxFileName::GetFullPath( wxPathFormat format ) const
1496
// we already have a function to get the path
1497
wxString fullpath = GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR,
1500
// now just add the file name and extension to it
1501
fullpath += GetFullName();
1506
// Return the short form of the path (returns identity on non-Windows platforms)
1507
wxString wxFileName::GetShortPath() const
1509
wxString path(GetFullPath());
1511
#if defined(__WXMSW__) && defined(__WIN32__) && !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
1512
DWORD sz = ::GetShortPathName(path, NULL, 0);
1516
if ( ::GetShortPathName
1519
wxStringBuffer(pathOut, sz),
1531
// Return the long form of the path (returns identity on non-Windows platforms)
1532
wxString wxFileName::GetLongPath() const
1535
path = GetFullPath();
1537
#if defined(__WIN32__) && !defined(__WXMICROWIN__)
1539
#if wxUSE_DYNAMIC_LOADER
1540
typedef DWORD (WINAPI *GET_LONG_PATH_NAME)(const wxChar *, wxChar *, DWORD);
1542
// this is MT-safe as in the worst case we're going to resolve the function
1543
// twice -- but as the result is the same in both threads, it's ok
1544
static GET_LONG_PATH_NAME s_pfnGetLongPathName = NULL;
1545
if ( !s_pfnGetLongPathName )
1547
static bool s_triedToLoad = false;
1549
if ( !s_triedToLoad )
1551
s_triedToLoad = true;
1553
wxDynamicLibrary dllKernel(_T("kernel32"));
1555
const wxChar* GetLongPathName = _T("GetLongPathName")
1560
#endif // Unicode/ANSI
1562
if ( dllKernel.HasSymbol(GetLongPathName) )
1564
s_pfnGetLongPathName = (GET_LONG_PATH_NAME)
1565
dllKernel.GetSymbol(GetLongPathName);
1568
// note that kernel32.dll can be unloaded, it stays in memory
1569
// anyhow as all Win32 programs link to it and so it's safe to call
1570
// GetLongPathName() even after unloading it
1574
if ( s_pfnGetLongPathName )
1576
DWORD dwSize = (*s_pfnGetLongPathName)(path, NULL, 0);
1579
if ( (*s_pfnGetLongPathName)
1582
wxStringBuffer(pathOut, dwSize),
1590
#endif // wxUSE_DYNAMIC_LOADER
1592
// The OS didn't support GetLongPathName, or some other error.
1593
// We need to call FindFirstFile on each component in turn.
1595
WIN32_FIND_DATA findFileData;
1599
pathOut = GetVolume() +
1600
GetVolumeSeparator(wxPATH_DOS) +
1601
GetPathSeparator(wxPATH_DOS);
1603
pathOut = wxEmptyString;
1605
wxArrayString dirs = GetDirs();
1606
dirs.Add(GetFullName());
1610
size_t count = dirs.GetCount();
1611
for ( size_t i = 0; i < count; i++ )
1613
// We're using pathOut to collect the long-name path, but using a
1614
// temporary for appending the last path component which may be
1616
tmpPath = pathOut + dirs[i];
1618
if ( tmpPath.empty() )
1621
// can't see this being necessary? MF
1622
if ( tmpPath.Last() == GetVolumeSeparator(wxPATH_DOS) )
1624
// Can't pass a drive and root dir to FindFirstFile,
1625
// so continue to next dir
1626
tmpPath += wxFILE_SEP_PATH;
1631
hFind = ::FindFirstFile(tmpPath, &findFileData);
1632
if (hFind == INVALID_HANDLE_VALUE)
1634
// Error: most likely reason is that path doesn't exist, so
1635
// append any unprocessed parts and return
1636
for ( i += 1; i < count; i++ )
1637
tmpPath += wxFILE_SEP_PATH + dirs[i];
1642
pathOut += findFileData.cFileName;
1643
if ( (i < (count-1)) )
1644
pathOut += wxFILE_SEP_PATH;
1650
#endif // Win32/!Win32
1655
wxPathFormat wxFileName::GetFormat( wxPathFormat format )
1657
if (format == wxPATH_NATIVE)
1659
#if defined(__WXMSW__) || defined(__OS2__) || defined(__DOS__)
1660
format = wxPATH_DOS;
1661
#elif defined(__WXMAC__) && !defined(__DARWIN__)
1662
format = wxPATH_MAC;
1663
#elif defined(__VMS)
1664
format = wxPATH_VMS;
1666
format = wxPATH_UNIX;
1672
// ----------------------------------------------------------------------------
1673
// path splitting function
1674
// ----------------------------------------------------------------------------
1678
wxFileName::SplitVolume(const wxString& fullpathWithVolume,
1679
wxString *pstrVolume,
1681
wxPathFormat format)
1683
format = GetFormat(format);
1685
wxString fullpath = fullpathWithVolume;
1687
// special Windows UNC paths hack: transform \\share\path into share:path
1688
if ( format == wxPATH_DOS )
1690
if ( fullpath.length() >= 4 &&
1691
fullpath[0u] == wxFILE_SEP_PATH_DOS &&
1692
fullpath[1u] == wxFILE_SEP_PATH_DOS )
1694
fullpath.erase(0, 2);
1696
size_t posFirstSlash =
1697
fullpath.find_first_of(GetPathTerminators(format));
1698
if ( posFirstSlash != wxString::npos )
1700
fullpath[posFirstSlash] = wxFILE_SEP_DSK;
1702
// UNC paths are always absolute, right? (FIXME)
1703
fullpath.insert(posFirstSlash + 1, 1, wxFILE_SEP_PATH_DOS);
1708
// We separate the volume here
1709
if ( format == wxPATH_DOS || format == wxPATH_VMS )
1711
wxString sepVol = GetVolumeSeparator(format);
1713
size_t posFirstColon = fullpath.find_first_of(sepVol);
1714
if ( posFirstColon != wxString::npos )
1718
*pstrVolume = fullpath.Left(posFirstColon);
1721
// remove the volume name and the separator from the full path
1722
fullpath.erase(0, posFirstColon + sepVol.length());
1727
*pstrPath = fullpath;
1731
void wxFileName::SplitPath(const wxString& fullpathWithVolume,
1732
wxString *pstrVolume,
1737
wxPathFormat format)
1739
format = GetFormat(format);
1742
SplitVolume(fullpathWithVolume, pstrVolume, &fullpath, format);
1744
// find the positions of the last dot and last path separator in the path
1745
size_t posLastDot = fullpath.find_last_of(wxFILE_SEP_EXT);
1746
size_t posLastSlash = fullpath.find_last_of(GetPathTerminators(format));
1748
// check whether this dot occurs at the very beginning of a path component
1749
if ( (posLastDot != wxString::npos) &&
1751
IsPathSeparator(fullpath[posLastDot - 1]) ||
1752
(format == wxPATH_VMS && fullpath[posLastDot - 1] == _T(']'))) )
1754
// dot may be (and commonly -- at least under Unix -- is) the first
1755
// character of the filename, don't treat the entire filename as
1756
// extension in this case
1757
posLastDot = wxString::npos;
1760
// if we do have a dot and a slash, check that the dot is in the name part
1761
if ( (posLastDot != wxString::npos) &&
1762
(posLastSlash != wxString::npos) &&
1763
(posLastDot < posLastSlash) )
1765
// the dot is part of the path, not the start of the extension
1766
posLastDot = wxString::npos;
1769
// now fill in the variables provided by user
1772
if ( posLastSlash == wxString::npos )
1779
// take everything up to the path separator but take care to make
1780
// the path equal to something like '/', not empty, for the files
1781
// immediately under root directory
1782
size_t len = posLastSlash;
1784
// this rule does not apply to mac since we do not start with colons (sep)
1785
// except for relative paths
1786
if ( !len && format != wxPATH_MAC)
1789
*pstrPath = fullpath.Left(len);
1791
// special VMS hack: remove the initial bracket
1792
if ( format == wxPATH_VMS )
1794
if ( (*pstrPath)[0u] == _T('[') )
1795
pstrPath->erase(0, 1);
1802
// take all characters starting from the one after the last slash and
1803
// up to, but excluding, the last dot
1804
size_t nStart = posLastSlash == wxString::npos ? 0 : posLastSlash + 1;
1806
if ( posLastDot == wxString::npos )
1808
// take all until the end
1809
count = wxString::npos;
1811
else if ( posLastSlash == wxString::npos )
1815
else // have both dot and slash
1817
count = posLastDot - posLastSlash - 1;
1820
*pstrName = fullpath.Mid(nStart, count);
1823
// finally deal with the extension here: we have an added complication that
1824
// extension may be empty (but present) as in "foo." where trailing dot
1825
// indicates the empty extension at the end -- and hence we must remember
1826
// that we have it independently of pstrExt
1827
if ( posLastDot == wxString::npos )
1837
// take everything after the dot
1839
*pstrExt = fullpath.Mid(posLastDot + 1);
1846
void wxFileName::SplitPath(const wxString& fullpath,
1850
wxPathFormat format)
1853
SplitPath(fullpath, &volume, path, name, ext, format);
1857
path->Prepend(wxGetVolumeString(volume, format));
1861
// ----------------------------------------------------------------------------
1863
// ----------------------------------------------------------------------------
1867
bool wxFileName::SetTimes(const wxDateTime *dtAccess,
1868
const wxDateTime *dtMod,
1869
const wxDateTime *dtCreate)
1871
#if defined(__WIN32__)
1874
// VZ: please let me know how to do this if you can
1875
wxFAIL_MSG( _T("SetTimes() not implemented for the directories") );
1879
wxFileHandle fh(GetFullPath(), wxFileHandle::Write);
1882
FILETIME ftAccess, ftCreate, ftWrite;
1885
ConvertWxToFileTime(&ftCreate, *dtCreate);
1887
ConvertWxToFileTime(&ftAccess, *dtAccess);
1889
ConvertWxToFileTime(&ftWrite, *dtMod);
1891
if ( ::SetFileTime(fh,
1892
dtCreate ? &ftCreate : NULL,
1893
dtAccess ? &ftAccess : NULL,
1894
dtMod ? &ftWrite : NULL) )
1900
#elif defined(__UNIX_LIKE__) || (defined(__DOS__) && defined(__WATCOMC__))
1901
wxUnusedVar(dtCreate);
1903
if ( !dtAccess && !dtMod )
1905
// can't modify the creation time anyhow, don't try
1909
// if dtAccess or dtMod is not specified, use the other one (which must be
1910
// non NULL because of the test above) for both times
1912
utm.actime = dtAccess ? dtAccess->GetTicks() : dtMod->GetTicks();
1913
utm.modtime = dtMod ? dtMod->GetTicks() : dtAccess->GetTicks();
1914
if ( utime(GetFullPath().fn_str(), &utm) == 0 )
1918
#else // other platform
1919
wxUnusedVar(dtAccess);
1921
wxUnusedVar(dtCreate);
1924
wxLogSysError(_("Failed to modify file times for '%s'"),
1925
GetFullPath().c_str());
1930
bool wxFileName::Touch()
1932
#if defined(__UNIX_LIKE__)
1933
// under Unix touching file is simple: just pass NULL to utime()
1934
if ( utime(GetFullPath().fn_str(), NULL) == 0 )
1939
wxLogSysError(_("Failed to touch the file '%s'"), GetFullPath().c_str());
1942
#else // other platform
1943
wxDateTime dtNow = wxDateTime::Now();
1945
return SetTimes(&dtNow, &dtNow, NULL /* don't change create time */);
1949
bool wxFileName::GetTimes(wxDateTime *dtAccess,
1951
wxDateTime *dtCreate) const
1953
#if defined(__WIN32__)
1954
// we must use different methods for the files and directories under
1955
// Windows as CreateFile(GENERIC_READ) doesn't work for the directories and
1956
// CreateFile(FILE_FLAG_BACKUP_SEMANTICS) works -- but only under NT and
1959
FILETIME ftAccess, ftCreate, ftWrite;
1962
// implemented in msw/dir.cpp
1963
extern bool wxGetDirectoryTimes(const wxString& dirname,
1964
FILETIME *, FILETIME *, FILETIME *);
1966
// we should pass the path without the trailing separator to
1967
// wxGetDirectoryTimes()
1968
ok = wxGetDirectoryTimes(GetPath(wxPATH_GET_VOLUME),
1969
&ftAccess, &ftCreate, &ftWrite);
1973
wxFileHandle fh(GetFullPath(), wxFileHandle::Read);
1976
ok = ::GetFileTime(fh,
1977
dtCreate ? &ftCreate : NULL,
1978
dtAccess ? &ftAccess : NULL,
1979
dtMod ? &ftWrite : NULL) != 0;
1990
ConvertFileTimeToWx(dtCreate, ftCreate);
1992
ConvertFileTimeToWx(dtAccess, ftAccess);
1994
ConvertFileTimeToWx(dtMod, ftWrite);
1998
#elif defined(__UNIX_LIKE__) || defined(__WXMAC__) || defined(__OS2__) || (defined(__DOS__) && defined(__WATCOMC__))
2000
if ( wxStat( GetFullPath().c_str(), &stBuf) == 0 )
2003
dtAccess->Set(stBuf.st_atime);
2005
dtMod->Set(stBuf.st_mtime);
2007
dtCreate->Set(stBuf.st_ctime);
2011
#else // other platform
2012
wxUnusedVar(dtAccess);
2014
wxUnusedVar(dtCreate);
2017
wxLogSysError(_("Failed to retrieve file times for '%s'"),
2018
GetFullPath().c_str());
2023
#endif // wxUSE_DATETIME
2027
const short kMacExtensionMaxLength = 16 ;
2028
class MacDefaultExtensionRecord
2031
MacDefaultExtensionRecord()
2034
m_type = m_creator = 0 ;
2036
MacDefaultExtensionRecord( const MacDefaultExtensionRecord& from )
2038
wxStrcpy( m_ext , from.m_ext ) ;
2039
m_type = from.m_type ;
2040
m_creator = from.m_creator ;
2042
MacDefaultExtensionRecord( const wxChar * extension , OSType type , OSType creator )
2044
wxStrncpy( m_ext , extension , kMacExtensionMaxLength ) ;
2045
m_ext[kMacExtensionMaxLength] = 0 ;
2047
m_creator = creator ;
2049
wxChar m_ext[kMacExtensionMaxLength] ;
2054
#include "wx/dynarray.h"
2055
WX_DECLARE_OBJARRAY(MacDefaultExtensionRecord, MacDefaultExtensionArray) ;
2057
bool gMacDefaultExtensionsInited = false ;
2059
#include "wx/arrimpl.cpp"
2061
WX_DEFINE_EXPORTED_OBJARRAY(MacDefaultExtensionArray) ;
2063
MacDefaultExtensionArray gMacDefaultExtensions ;
2065
// load the default extensions
2066
MacDefaultExtensionRecord gDefaults[] =
2068
MacDefaultExtensionRecord( wxT("txt") , 'TEXT' , 'ttxt' ) ,
2069
MacDefaultExtensionRecord( wxT("tif") , 'TIFF' , '****' ) ,
2070
MacDefaultExtensionRecord( wxT("jpg") , 'JPEG' , '****' ) ,
2073
static void MacEnsureDefaultExtensionsLoaded()
2075
if ( !gMacDefaultExtensionsInited )
2077
// we could load the pc exchange prefs here too
2078
for ( size_t i = 0 ; i < WXSIZEOF( gDefaults ) ; ++i )
2080
gMacDefaultExtensions.Add( gDefaults[i] ) ;
2082
gMacDefaultExtensionsInited = true ;
2086
bool wxFileName::MacSetTypeAndCreator( wxUint32 type , wxUint32 creator )
2089
FSCatalogInfo catInfo;
2092
if ( wxMacPathToFSRef( GetFullPath() , &fsRef ) == noErr )
2094
if ( FSGetCatalogInfo (&fsRef, kFSCatInfoFinderInfo, &catInfo, NULL, NULL, NULL) == noErr )
2096
finfo = (FileInfo*)&catInfo.finderInfo;
2097
finfo->fileType = type ;
2098
finfo->fileCreator = creator ;
2099
FSSetCatalogInfo( &fsRef, kFSCatInfoFinderInfo, &catInfo ) ;
2106
bool wxFileName::MacGetTypeAndCreator( wxUint32 *type , wxUint32 *creator )
2109
FSCatalogInfo catInfo;
2112
if ( wxMacPathToFSRef( GetFullPath() , &fsRef ) == noErr )
2114
if ( FSGetCatalogInfo (&fsRef, kFSCatInfoFinderInfo, &catInfo, NULL, NULL, NULL) == noErr )
2116
finfo = (FileInfo*)&catInfo.finderInfo;
2117
*type = finfo->fileType ;
2118
*creator = finfo->fileCreator ;
2125
bool wxFileName::MacSetDefaultTypeAndCreator()
2127
wxUint32 type , creator ;
2128
if ( wxFileName::MacFindDefaultTypeAndCreator(GetExt() , &type ,
2131
return MacSetTypeAndCreator( type , creator ) ;
2136
bool wxFileName::MacFindDefaultTypeAndCreator( const wxString& ext , wxUint32 *type , wxUint32 *creator )
2138
MacEnsureDefaultExtensionsLoaded() ;
2139
wxString extl = ext.Lower() ;
2140
for( int i = gMacDefaultExtensions.Count() - 1 ; i >= 0 ; --i )
2142
if ( gMacDefaultExtensions.Item(i).m_ext == extl )
2144
*type = gMacDefaultExtensions.Item(i).m_type ;
2145
*creator = gMacDefaultExtensions.Item(i).m_creator ;
2152
void wxFileName::MacRegisterDefaultTypeAndCreator( const wxString& ext , wxUint32 type , wxUint32 creator )
2154
MacEnsureDefaultExtensionsLoaded() ;
2155
MacDefaultExtensionRecord rec ;
2157
rec.m_creator = creator ;
2158
wxStrncpy( rec.m_ext , ext.Lower().c_str() , kMacExtensionMaxLength ) ;
2159
gMacDefaultExtensions.Add( rec ) ;