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