1 |
william |
31 |
///////////////////////////////////////////////////////////////////////////// |
2 |
|
|
// Name: src/common/filesys.cpp |
3 |
|
|
// Purpose: wxFileSystem class - interface for opening files |
4 |
|
|
// Author: Vaclav Slavik |
5 |
|
|
// Copyright: (c) 1999 Vaclav Slavik |
6 |
|
|
// CVS-ID: $Id: filesys.cpp 55271 2008-08-26 00:03:04Z VZ $ |
7 |
|
|
// Licence: wxWindows licence |
8 |
|
|
///////////////////////////////////////////////////////////////////////////// |
9 |
|
|
|
10 |
|
|
#include "wx/wxprec.h" |
11 |
|
|
|
12 |
|
|
#ifdef __BORLANDC__ |
13 |
|
|
#pragma hdrstop |
14 |
|
|
#endif |
15 |
|
|
|
16 |
|
|
|
17 |
|
|
#if wxUSE_FILESYSTEM |
18 |
|
|
|
19 |
|
|
#include "wx/filesys.h" |
20 |
|
|
|
21 |
|
|
#ifndef WX_PRECOMP |
22 |
|
|
#include "wx/log.h" |
23 |
|
|
#include "wx/module.h" |
24 |
|
|
#endif |
25 |
|
|
|
26 |
|
|
#include "wx/sysopt.h" |
27 |
|
|
#include "wx/wfstream.h" |
28 |
|
|
#include "wx/mimetype.h" |
29 |
|
|
#include "wx/filename.h" |
30 |
|
|
#include "wx/tokenzr.h" |
31 |
|
|
#include "wx/uri.h" |
32 |
|
|
#include "wx/private/fileback.h" |
33 |
|
|
|
34 |
|
|
|
35 |
|
|
//-------------------------------------------------------------------------------- |
36 |
|
|
// wxFileSystemHandler |
37 |
|
|
//-------------------------------------------------------------------------------- |
38 |
|
|
|
39 |
|
|
IMPLEMENT_ABSTRACT_CLASS(wxFileSystemHandler, wxObject) |
40 |
|
|
|
41 |
|
|
|
42 |
|
|
wxString wxFileSystemHandler::GetMimeTypeFromExt(const wxString& location) |
43 |
|
|
{ |
44 |
|
|
wxString ext, mime; |
45 |
|
|
wxString loc = GetRightLocation(location); |
46 |
|
|
wxChar c; |
47 |
|
|
int l = loc.length(), l2; |
48 |
|
|
|
49 |
|
|
l2 = l; |
50 |
|
|
for (int i = l-1; i >= 0; i--) |
51 |
|
|
{ |
52 |
|
|
c = loc[(unsigned int) i]; |
53 |
|
|
if ( c == wxT('#') ) |
54 |
|
|
l2 = i + 1; |
55 |
|
|
if ( c == wxT('.') ) |
56 |
|
|
{ |
57 |
|
|
ext = loc.Right(l2-i-1); |
58 |
|
|
break; |
59 |
|
|
} |
60 |
|
|
if ( (c == wxT('/')) || (c == wxT('\\')) || (c == wxT(':')) ) |
61 |
|
|
return wxEmptyString; |
62 |
|
|
} |
63 |
|
|
|
64 |
|
|
#if wxUSE_MIMETYPE |
65 |
|
|
static bool s_MinimalMimeEnsured = false; |
66 |
|
|
|
67 |
|
|
// Don't use mime types manager if the application doesn't need it and it would be |
68 |
|
|
// cause an unacceptable delay, especially on startup. |
69 |
|
|
bool useMimeTypesManager = true; |
70 |
|
|
#if wxUSE_SYSTEM_OPTIONS |
71 |
|
|
useMimeTypesManager = (wxSystemOptions::GetOptionInt(wxT("filesys.no-mimetypesmanager")) == 0); |
72 |
|
|
#endif |
73 |
|
|
|
74 |
|
|
if (useMimeTypesManager) |
75 |
|
|
{ |
76 |
|
|
if (!s_MinimalMimeEnsured) |
77 |
|
|
{ |
78 |
|
|
static const wxFileTypeInfo fallbacks[] = |
79 |
|
|
{ |
80 |
|
|
wxFileTypeInfo(_T("image/jpeg"), |
81 |
|
|
wxEmptyString, |
82 |
|
|
wxEmptyString, |
83 |
|
|
_T("JPEG image (from fallback)"), |
84 |
|
|
_T("jpg"), _T("jpeg"), _T("JPG"), _T("JPEG"), NULL), |
85 |
|
|
wxFileTypeInfo(_T("image/gif"), |
86 |
|
|
wxEmptyString, |
87 |
|
|
wxEmptyString, |
88 |
|
|
_T("GIF image (from fallback)"), |
89 |
|
|
_T("gif"), _T("GIF"), NULL), |
90 |
|
|
wxFileTypeInfo(_T("image/png"), |
91 |
|
|
wxEmptyString, |
92 |
|
|
wxEmptyString, |
93 |
|
|
_T("PNG image (from fallback)"), |
94 |
|
|
_T("png"), _T("PNG"), NULL), |
95 |
|
|
wxFileTypeInfo(_T("image/bmp"), |
96 |
|
|
wxEmptyString, |
97 |
|
|
wxEmptyString, |
98 |
|
|
_T("windows bitmap image (from fallback)"), |
99 |
|
|
_T("bmp"), _T("BMP"), NULL), |
100 |
|
|
wxFileTypeInfo(_T("text/html"), |
101 |
|
|
wxEmptyString, |
102 |
|
|
wxEmptyString, |
103 |
|
|
_T("HTML document (from fallback)"), |
104 |
|
|
_T("htm"), _T("html"), _T("HTM"), _T("HTML"), NULL), |
105 |
|
|
// must terminate the table with this! |
106 |
|
|
wxFileTypeInfo() |
107 |
|
|
}; |
108 |
|
|
wxTheMimeTypesManager->AddFallbacks(fallbacks); |
109 |
|
|
s_MinimalMimeEnsured = true; |
110 |
|
|
} |
111 |
|
|
|
112 |
|
|
wxFileType *ft = wxTheMimeTypesManager->GetFileTypeFromExtension(ext); |
113 |
|
|
if ( !ft || !ft -> GetMimeType(&mime) ) |
114 |
|
|
{ |
115 |
|
|
mime = wxEmptyString; |
116 |
|
|
} |
117 |
|
|
|
118 |
|
|
delete ft; |
119 |
|
|
|
120 |
|
|
return mime; |
121 |
|
|
} |
122 |
|
|
else |
123 |
|
|
#endif |
124 |
|
|
{ |
125 |
|
|
if ( ext.IsSameAs(wxT("htm"), false) || ext.IsSameAs(_T("html"), false) ) |
126 |
|
|
return wxT("text/html"); |
127 |
|
|
if ( ext.IsSameAs(wxT("jpg"), false) || ext.IsSameAs(_T("jpeg"), false) ) |
128 |
|
|
return wxT("image/jpeg"); |
129 |
|
|
if ( ext.IsSameAs(wxT("gif"), false) ) |
130 |
|
|
return wxT("image/gif"); |
131 |
|
|
if ( ext.IsSameAs(wxT("png"), false) ) |
132 |
|
|
return wxT("image/png"); |
133 |
|
|
if ( ext.IsSameAs(wxT("bmp"), false) ) |
134 |
|
|
return wxT("image/bmp"); |
135 |
|
|
return wxEmptyString; |
136 |
|
|
} |
137 |
|
|
} |
138 |
|
|
|
139 |
|
|
|
140 |
|
|
|
141 |
|
|
wxString wxFileSystemHandler::GetProtocol(const wxString& location) const |
142 |
|
|
{ |
143 |
|
|
wxString s = wxEmptyString; |
144 |
|
|
int i, l = location.length(); |
145 |
|
|
bool fnd = false; |
146 |
|
|
|
147 |
|
|
for (i = l-1; (i >= 0) && ((location[i] != wxT('#')) || (!fnd)); i--) { |
148 |
|
|
if ((location[i] == wxT(':')) && (i != 1 /*win: C:\path*/)) fnd = true; |
149 |
|
|
} |
150 |
|
|
if (!fnd) return wxT("file"); |
151 |
|
|
for (++i; (i < l) && (location[i] != wxT(':')); i++) s << location[i]; |
152 |
|
|
return s; |
153 |
|
|
} |
154 |
|
|
|
155 |
|
|
|
156 |
|
|
wxString wxFileSystemHandler::GetLeftLocation(const wxString& location) const |
157 |
|
|
{ |
158 |
|
|
int i; |
159 |
|
|
bool fnd = false; |
160 |
|
|
|
161 |
|
|
for (i = location.length()-1; i >= 0; i--) { |
162 |
|
|
if ((location[i] == wxT(':')) && (i != 1 /*win: C:\path*/)) fnd = true; |
163 |
|
|
else if (fnd && (location[i] == wxT('#'))) return location.Left(i); |
164 |
|
|
} |
165 |
|
|
return wxEmptyString; |
166 |
|
|
} |
167 |
|
|
|
168 |
|
|
wxString wxFileSystemHandler::GetRightLocation(const wxString& location) const |
169 |
|
|
{ |
170 |
|
|
int i, l = location.length(); |
171 |
|
|
int l2 = l + 1; |
172 |
|
|
|
173 |
|
|
for (i = l-1; |
174 |
|
|
(i >= 0) && |
175 |
|
|
((location[i] != wxT(':')) || (i == 1) || (location[i-2] == wxT(':'))); |
176 |
|
|
i--) |
177 |
|
|
{ |
178 |
|
|
if (location[i] == wxT('#')) l2 = i + 1; |
179 |
|
|
} |
180 |
|
|
if (i == 0) return wxEmptyString; |
181 |
|
|
else return location.Mid(i + 1, l2 - i - 2); |
182 |
|
|
} |
183 |
|
|
|
184 |
|
|
wxString wxFileSystemHandler::GetAnchor(const wxString& location) const |
185 |
|
|
{ |
186 |
|
|
wxChar c; |
187 |
|
|
int l = location.length(); |
188 |
|
|
|
189 |
|
|
for (int i = l-1; i >= 0; i--) { |
190 |
|
|
c = location[i]; |
191 |
|
|
if (c == wxT('#')) |
192 |
|
|
return location.Right(l-i-1); |
193 |
|
|
else if ((c == wxT('/')) || (c == wxT('\\')) || (c == wxT(':'))) |
194 |
|
|
return wxEmptyString; |
195 |
|
|
} |
196 |
|
|
return wxEmptyString; |
197 |
|
|
} |
198 |
|
|
|
199 |
|
|
|
200 |
|
|
wxString wxFileSystemHandler::FindFirst(const wxString& WXUNUSED(spec), |
201 |
|
|
int WXUNUSED(flags)) |
202 |
|
|
{ |
203 |
|
|
return wxEmptyString; |
204 |
|
|
} |
205 |
|
|
|
206 |
|
|
wxString wxFileSystemHandler::FindNext() |
207 |
|
|
{ |
208 |
|
|
return wxEmptyString; |
209 |
|
|
} |
210 |
|
|
|
211 |
|
|
//-------------------------------------------------------------------------------- |
212 |
|
|
// wxLocalFSHandler |
213 |
|
|
//-------------------------------------------------------------------------------- |
214 |
|
|
|
215 |
|
|
|
216 |
|
|
wxString wxLocalFSHandler::ms_root; |
217 |
|
|
|
218 |
|
|
bool wxLocalFSHandler::CanOpen(const wxString& location) |
219 |
|
|
{ |
220 |
|
|
return GetProtocol(location) == wxT("file"); |
221 |
|
|
} |
222 |
|
|
|
223 |
|
|
wxFSFile* wxLocalFSHandler::OpenFile(wxFileSystem& WXUNUSED(fs), const wxString& location) |
224 |
|
|
{ |
225 |
|
|
// location has Unix path separators |
226 |
|
|
wxString right = GetRightLocation(location); |
227 |
|
|
wxFileName fn = wxFileSystem::URLToFileName(right); |
228 |
|
|
wxString fullpath = ms_root + fn.GetFullPath(); |
229 |
|
|
|
230 |
|
|
if (!wxFileExists(fullpath)) |
231 |
|
|
return (wxFSFile*) NULL; |
232 |
|
|
|
233 |
|
|
// we need to check whether we can really read from this file, otherwise |
234 |
|
|
// wxFSFile is not going to work |
235 |
|
|
#if wxUSE_FFILE |
236 |
|
|
wxFFileInputStream *is = new wxFFileInputStream(fullpath); |
237 |
|
|
#elif wxUSE_FILE |
238 |
|
|
wxFileInputStream *is = new wxFileInputStream(fullpath); |
239 |
|
|
#else |
240 |
|
|
#error One of wxUSE_FILE or wxUSE_FFILE must be set to 1 for wxFSHandler to work |
241 |
|
|
#endif |
242 |
|
|
if ( !is->Ok() ) |
243 |
|
|
{ |
244 |
|
|
delete is; |
245 |
|
|
return (wxFSFile*) NULL; |
246 |
|
|
} |
247 |
|
|
|
248 |
|
|
return new wxFSFile(is, |
249 |
|
|
right, |
250 |
|
|
GetMimeTypeFromExt(location), |
251 |
|
|
GetAnchor(location) |
252 |
|
|
#if wxUSE_DATETIME |
253 |
|
|
,wxDateTime(wxFileModificationTime(fullpath)) |
254 |
|
|
#endif // wxUSE_DATETIME |
255 |
|
|
); |
256 |
|
|
} |
257 |
|
|
|
258 |
|
|
wxString wxLocalFSHandler::FindFirst(const wxString& spec, int flags) |
259 |
|
|
{ |
260 |
|
|
wxFileName fn = wxFileSystem::URLToFileName(GetRightLocation(spec)); |
261 |
|
|
return wxFindFirstFile(ms_root + fn.GetFullPath(), flags); |
262 |
|
|
} |
263 |
|
|
|
264 |
|
|
wxString wxLocalFSHandler::FindNext() |
265 |
|
|
{ |
266 |
|
|
return wxFindNextFile(); |
267 |
|
|
} |
268 |
|
|
|
269 |
|
|
|
270 |
|
|
|
271 |
|
|
//----------------------------------------------------------------------------- |
272 |
|
|
// wxFileSystem |
273 |
|
|
//----------------------------------------------------------------------------- |
274 |
|
|
|
275 |
|
|
IMPLEMENT_DYNAMIC_CLASS(wxFileSystem, wxObject) |
276 |
|
|
IMPLEMENT_ABSTRACT_CLASS(wxFSFile, wxObject) |
277 |
|
|
|
278 |
|
|
|
279 |
|
|
wxList wxFileSystem::m_Handlers; |
280 |
|
|
|
281 |
|
|
|
282 |
|
|
wxFileSystem::~wxFileSystem() |
283 |
|
|
{ |
284 |
|
|
WX_CLEAR_HASH_MAP(wxFSHandlerHash, m_LocalHandlers) |
285 |
|
|
} |
286 |
|
|
|
287 |
|
|
|
288 |
|
|
static wxString MakeCorrectPath(const wxString& path) |
289 |
|
|
{ |
290 |
|
|
wxString p(path); |
291 |
|
|
wxString r; |
292 |
|
|
int i, j, cnt; |
293 |
|
|
|
294 |
|
|
cnt = p.length(); |
295 |
|
|
for (i = 0; i < cnt; i++) |
296 |
|
|
if (p.GetChar(i) == wxT('\\')) p.GetWritableChar(i) = wxT('/'); // Want to be windows-safe |
297 |
|
|
|
298 |
|
|
if (p.Left(2) == wxT("./")) { p = p.Mid(2); cnt -= 2; } |
299 |
|
|
|
300 |
|
|
if (cnt < 3) return p; |
301 |
|
|
|
302 |
|
|
r << p.GetChar(0) << p.GetChar(1); |
303 |
|
|
|
304 |
|
|
// skip trailing ../.., if any |
305 |
|
|
for (i = 2; i < cnt && (p.GetChar(i) == wxT('/') || p.GetChar(i) == wxT('.')); i++) r << p.GetChar(i); |
306 |
|
|
|
307 |
|
|
// remove back references: translate dir1/../dir2 to dir2 |
308 |
|
|
for (; i < cnt; i++) |
309 |
|
|
{ |
310 |
|
|
r << p.GetChar(i); |
311 |
|
|
if (p.GetChar(i) == wxT('/') && p.GetChar(i-1) == wxT('.') && p.GetChar(i-2) == wxT('.')) |
312 |
|
|
{ |
313 |
|
|
for (j = r.length() - 2; j >= 0 && r.GetChar(j) != wxT('/') && r.GetChar(j) != wxT(':'); j--) {} |
314 |
|
|
if (j >= 0 && r.GetChar(j) != wxT(':')) |
315 |
|
|
{ |
316 |
|
|
for (j = j - 1; j >= 0 && r.GetChar(j) != wxT('/') && r.GetChar(j) != wxT(':'); j--) {} |
317 |
|
|
r.Remove(j + 1); |
318 |
|
|
} |
319 |
|
|
} |
320 |
|
|
} |
321 |
|
|
|
322 |
|
|
for (; i < cnt; i++) r << p.GetChar(i); |
323 |
|
|
|
324 |
|
|
return r; |
325 |
|
|
} |
326 |
|
|
|
327 |
|
|
|
328 |
|
|
void wxFileSystem::ChangePathTo(const wxString& location, bool is_dir) |
329 |
|
|
{ |
330 |
|
|
int i, pathpos = -1; |
331 |
|
|
|
332 |
|
|
m_Path = MakeCorrectPath(location); |
333 |
|
|
|
334 |
|
|
if (is_dir) |
335 |
|
|
{ |
336 |
|
|
if (m_Path.length() > 0 && m_Path.Last() != wxT('/') && m_Path.Last() != wxT(':')) |
337 |
|
|
m_Path << wxT('/'); |
338 |
|
|
} |
339 |
|
|
|
340 |
|
|
else |
341 |
|
|
{ |
342 |
|
|
for (i = m_Path.length()-1; i >= 0; i--) |
343 |
|
|
{ |
344 |
|
|
if (m_Path[(unsigned int) i] == wxT('/')) |
345 |
|
|
{ |
346 |
|
|
if ((i > 1) && (m_Path[(unsigned int) (i-1)] == wxT('/')) && (m_Path[(unsigned int) (i-2)] == wxT(':'))) |
347 |
|
|
{ |
348 |
|
|
i -= 2; |
349 |
|
|
continue; |
350 |
|
|
} |
351 |
|
|
else |
352 |
|
|
{ |
353 |
|
|
pathpos = i; |
354 |
|
|
break; |
355 |
|
|
} |
356 |
|
|
} |
357 |
|
|
else if (m_Path[(unsigned int) i] == wxT(':')) { |
358 |
|
|
pathpos = i; |
359 |
|
|
break; |
360 |
|
|
} |
361 |
|
|
} |
362 |
|
|
if (pathpos == -1) |
363 |
|
|
{ |
364 |
|
|
for (i = 0; i < (int) m_Path.length(); i++) |
365 |
|
|
{ |
366 |
|
|
if (m_Path[(unsigned int) i] == wxT(':')) |
367 |
|
|
{ |
368 |
|
|
m_Path.Remove(i+1); |
369 |
|
|
break; |
370 |
|
|
} |
371 |
|
|
} |
372 |
|
|
if (i == (int) m_Path.length()) |
373 |
|
|
m_Path = wxEmptyString; |
374 |
|
|
} |
375 |
|
|
else |
376 |
|
|
{ |
377 |
|
|
m_Path.Remove(pathpos+1); |
378 |
|
|
} |
379 |
|
|
} |
380 |
|
|
} |
381 |
|
|
|
382 |
|
|
|
383 |
|
|
|
384 |
|
|
wxFileSystemHandler *wxFileSystem::MakeLocal(wxFileSystemHandler *h) |
385 |
|
|
{ |
386 |
|
|
wxClassInfo *classinfo = h->GetClassInfo(); |
387 |
|
|
|
388 |
|
|
if (classinfo->IsDynamic()) |
389 |
|
|
{ |
390 |
|
|
wxFileSystemHandler*& local = m_LocalHandlers[classinfo]; |
391 |
|
|
if (!local) |
392 |
|
|
local = (wxFileSystemHandler*)classinfo->CreateObject(); |
393 |
|
|
return local; |
394 |
|
|
} |
395 |
|
|
else |
396 |
|
|
{ |
397 |
|
|
return h; |
398 |
|
|
} |
399 |
|
|
} |
400 |
|
|
|
401 |
|
|
|
402 |
|
|
|
403 |
|
|
wxFSFile* wxFileSystem::OpenFile(const wxString& location, int flags) |
404 |
|
|
{ |
405 |
|
|
if ((flags & wxFS_READ) == 0) |
406 |
|
|
return NULL; |
407 |
|
|
|
408 |
|
|
wxString loc = MakeCorrectPath(location); |
409 |
|
|
unsigned i, ln; |
410 |
|
|
wxChar meta; |
411 |
|
|
wxFSFile *s = NULL; |
412 |
|
|
wxList::compatibility_iterator node; |
413 |
|
|
|
414 |
|
|
ln = loc.length(); |
415 |
|
|
meta = 0; |
416 |
|
|
for (i = 0; i < ln; i++) |
417 |
|
|
{ |
418 |
|
|
switch (loc[i]) |
419 |
|
|
{ |
420 |
|
|
case wxT('/') : case wxT(':') : case wxT('#') : |
421 |
|
|
meta = loc[i]; |
422 |
|
|
break; |
423 |
|
|
} |
424 |
|
|
if (meta != 0) break; |
425 |
|
|
} |
426 |
|
|
m_LastName = wxEmptyString; |
427 |
|
|
|
428 |
|
|
// try relative paths first : |
429 |
|
|
if (meta != wxT(':')) |
430 |
|
|
{ |
431 |
|
|
node = m_Handlers.GetFirst(); |
432 |
|
|
while (node) |
433 |
|
|
{ |
434 |
|
|
wxFileSystemHandler *h = (wxFileSystemHandler*) node -> GetData(); |
435 |
|
|
if (h->CanOpen(m_Path + loc)) |
436 |
|
|
{ |
437 |
|
|
s = MakeLocal(h)->OpenFile(*this, m_Path + loc); |
438 |
|
|
if (s) { m_LastName = m_Path + loc; break; } |
439 |
|
|
} |
440 |
|
|
node = node->GetNext(); |
441 |
|
|
} |
442 |
|
|
} |
443 |
|
|
|
444 |
|
|
// if failed, try absolute paths : |
445 |
|
|
if (s == NULL) |
446 |
|
|
{ |
447 |
|
|
node = m_Handlers.GetFirst(); |
448 |
|
|
while (node) |
449 |
|
|
{ |
450 |
|
|
wxFileSystemHandler *h = (wxFileSystemHandler*) node->GetData(); |
451 |
|
|
if (h->CanOpen(loc)) |
452 |
|
|
{ |
453 |
|
|
s = MakeLocal(h)->OpenFile(*this, loc); |
454 |
|
|
if (s) { m_LastName = loc; break; } |
455 |
|
|
} |
456 |
|
|
node = node->GetNext(); |
457 |
|
|
} |
458 |
|
|
} |
459 |
|
|
|
460 |
|
|
if (s && (flags & wxFS_SEEKABLE) != 0 && !s->GetStream()->IsSeekable()) |
461 |
|
|
{ |
462 |
|
|
wxBackedInputStream *stream; |
463 |
|
|
stream = new wxBackedInputStream(s->DetachStream()); |
464 |
|
|
stream->FindLength(); |
465 |
|
|
s->SetStream(stream); |
466 |
|
|
} |
467 |
|
|
|
468 |
|
|
return (s); |
469 |
|
|
} |
470 |
|
|
|
471 |
|
|
|
472 |
|
|
|
473 |
|
|
wxString wxFileSystem::FindFirst(const wxString& spec, int flags) |
474 |
|
|
{ |
475 |
|
|
wxList::compatibility_iterator node; |
476 |
|
|
wxString spec2(spec); |
477 |
|
|
|
478 |
|
|
m_FindFileHandler = NULL; |
479 |
|
|
|
480 |
|
|
for (int i = spec2.length()-1; i >= 0; i--) |
481 |
|
|
if (spec2[(unsigned int) i] == wxT('\\')) spec2.GetWritableChar(i) = wxT('/'); // Want to be windows-safe |
482 |
|
|
|
483 |
|
|
node = m_Handlers.GetFirst(); |
484 |
|
|
while (node) |
485 |
|
|
{ |
486 |
|
|
wxFileSystemHandler *h = (wxFileSystemHandler*) node -> GetData(); |
487 |
|
|
if (h -> CanOpen(m_Path + spec2)) |
488 |
|
|
{ |
489 |
|
|
m_FindFileHandler = MakeLocal(h); |
490 |
|
|
return m_FindFileHandler -> FindFirst(m_Path + spec2, flags); |
491 |
|
|
} |
492 |
|
|
node = node->GetNext(); |
493 |
|
|
} |
494 |
|
|
|
495 |
|
|
node = m_Handlers.GetFirst(); |
496 |
|
|
while (node) |
497 |
|
|
{ |
498 |
|
|
wxFileSystemHandler *h = (wxFileSystemHandler*) node -> GetData(); |
499 |
|
|
if (h -> CanOpen(spec2)) |
500 |
|
|
{ |
501 |
|
|
m_FindFileHandler = MakeLocal(h); |
502 |
|
|
return m_FindFileHandler -> FindFirst(spec2, flags); |
503 |
|
|
} |
504 |
|
|
node = node->GetNext(); |
505 |
|
|
} |
506 |
|
|
|
507 |
|
|
return wxEmptyString; |
508 |
|
|
} |
509 |
|
|
|
510 |
|
|
|
511 |
|
|
|
512 |
|
|
wxString wxFileSystem::FindNext() |
513 |
|
|
{ |
514 |
|
|
if (m_FindFileHandler == NULL) return wxEmptyString; |
515 |
|
|
else return m_FindFileHandler -> FindNext(); |
516 |
|
|
} |
517 |
|
|
|
518 |
|
|
bool wxFileSystem::FindFileInPath(wxString *pStr, |
519 |
|
|
const wxChar *path, |
520 |
|
|
const wxChar *basename) |
521 |
|
|
{ |
522 |
|
|
// we assume that it's not empty |
523 |
|
|
wxCHECK_MSG( !wxIsEmpty(basename), false, |
524 |
|
|
_T("empty file name in wxFileSystem::FindFileInPath")); |
525 |
|
|
|
526 |
|
|
// skip path separator in the beginning of the file name if present |
527 |
|
|
if ( wxIsPathSeparator(*basename) ) |
528 |
|
|
basename++; |
529 |
|
|
|
530 |
|
|
wxStringTokenizer tokenizer(path, wxPATH_SEP); |
531 |
|
|
while ( tokenizer.HasMoreTokens() ) |
532 |
|
|
{ |
533 |
|
|
wxString strFile = tokenizer.GetNextToken(); |
534 |
|
|
if ( !wxEndsWithPathSeparator(strFile) ) |
535 |
|
|
strFile += wxFILE_SEP_PATH; |
536 |
|
|
strFile += basename; |
537 |
|
|
|
538 |
|
|
wxFSFile *file = OpenFile(strFile); |
539 |
|
|
if ( file ) |
540 |
|
|
{ |
541 |
|
|
delete file; |
542 |
|
|
*pStr = strFile; |
543 |
|
|
return true; |
544 |
|
|
} |
545 |
|
|
} |
546 |
|
|
|
547 |
|
|
return false; |
548 |
|
|
} |
549 |
|
|
|
550 |
|
|
void wxFileSystem::AddHandler(wxFileSystemHandler *handler) |
551 |
|
|
{ |
552 |
|
|
// prepend the handler to the beginning of the list because handlers added |
553 |
|
|
// last should have the highest priority to allow overriding them |
554 |
|
|
m_Handlers.Insert((size_t)0, handler); |
555 |
|
|
} |
556 |
|
|
|
557 |
|
|
wxFileSystemHandler* wxFileSystem::RemoveHandler(wxFileSystemHandler *handler) |
558 |
|
|
{ |
559 |
|
|
// if handler has already been removed (or deleted) |
560 |
|
|
// we return NULL. This is by design in case |
561 |
|
|
// CleanUpHandlers() is called before RemoveHandler |
562 |
|
|
// is called, as we cannot control the order |
563 |
|
|
// which modules are unloaded |
564 |
|
|
if (!m_Handlers.DeleteObject(handler)) |
565 |
|
|
return NULL; |
566 |
|
|
|
567 |
|
|
return handler; |
568 |
|
|
} |
569 |
|
|
|
570 |
|
|
|
571 |
|
|
bool wxFileSystem::HasHandlerForPath(const wxString &location) |
572 |
|
|
{ |
573 |
|
|
for ( wxList::compatibility_iterator node = m_Handlers.GetFirst(); |
574 |
|
|
node; node = node->GetNext() ) |
575 |
|
|
{ |
576 |
|
|
wxFileSystemHandler *h = (wxFileSystemHandler*) node->GetData(); |
577 |
|
|
if (h->CanOpen(location)) |
578 |
|
|
return true; |
579 |
|
|
} |
580 |
|
|
|
581 |
|
|
return false; |
582 |
|
|
} |
583 |
|
|
|
584 |
|
|
void wxFileSystem::CleanUpHandlers() |
585 |
|
|
{ |
586 |
|
|
WX_CLEAR_LIST(wxList, m_Handlers); |
587 |
|
|
} |
588 |
|
|
|
589 |
|
|
static const wxString g_unixPathString(wxT("/")); |
590 |
|
|
static const wxString g_nativePathString(wxFILE_SEP_PATH); |
591 |
|
|
|
592 |
|
|
// Returns the native path for a file URL |
593 |
|
|
wxFileName wxFileSystem::URLToFileName(const wxString& url) |
594 |
|
|
{ |
595 |
|
|
wxString path = url; |
596 |
|
|
|
597 |
|
|
if ( path.Find(wxT("file://")) == 0 ) |
598 |
|
|
{ |
599 |
|
|
path = path.Mid(7); |
600 |
|
|
} |
601 |
|
|
else if ( path.Find(wxT("file:")) == 0 ) |
602 |
|
|
{ |
603 |
|
|
path = path.Mid(5); |
604 |
|
|
} |
605 |
|
|
// Remove preceding double slash on Mac Classic |
606 |
|
|
#if defined(__WXMAC__) && !defined(__UNIX__) |
607 |
|
|
else if ( path.Find(wxT("//")) == 0 ) |
608 |
|
|
path = path.Mid(2); |
609 |
|
|
#endif |
610 |
|
|
|
611 |
|
|
path = wxURI::Unescape(path); |
612 |
|
|
|
613 |
|
|
#ifdef __WXMSW__ |
614 |
|
|
// file urls either start with a forward slash (local harddisk), |
615 |
|
|
// otherwise they have a servername/sharename notation, |
616 |
|
|
// which only exists on msw and corresponds to a unc |
617 |
|
|
if ( path[0u] == wxT('/') && path [1u] != wxT('/')) |
618 |
|
|
{ |
619 |
|
|
path = path.Mid(1); |
620 |
|
|
} |
621 |
|
|
else if ( (url.Find(wxT("file://")) == 0) && |
622 |
|
|
(path.Find(wxT('/')) != wxNOT_FOUND) && |
623 |
|
|
(path.length() > 1) && (path[1u] != wxT(':')) ) |
624 |
|
|
{ |
625 |
|
|
path = wxT("//") + path; |
626 |
|
|
} |
627 |
|
|
#endif |
628 |
|
|
|
629 |
|
|
path.Replace(g_unixPathString, g_nativePathString); |
630 |
|
|
|
631 |
|
|
return wxFileName(path, wxPATH_NATIVE); |
632 |
|
|
} |
633 |
|
|
|
634 |
|
|
// Returns the file URL for a native path |
635 |
|
|
wxString wxFileSystem::FileNameToURL(const wxFileName& filename) |
636 |
|
|
{ |
637 |
|
|
wxFileName fn = filename; |
638 |
|
|
fn.Normalize(wxPATH_NORM_DOTS | wxPATH_NORM_TILDE | wxPATH_NORM_ABSOLUTE); |
639 |
|
|
wxString url = fn.GetFullPath(wxPATH_NATIVE); |
640 |
|
|
|
641 |
|
|
#ifndef __UNIX__ |
642 |
|
|
// unc notation, wxMSW |
643 |
|
|
if ( url.Find(wxT("\\\\")) == 0 ) |
644 |
|
|
{ |
645 |
|
|
url = wxT("//") + url.Mid(2); |
646 |
|
|
} |
647 |
|
|
else |
648 |
|
|
{ |
649 |
|
|
url = wxT("/") + url; |
650 |
|
|
#ifdef __WXMAC__ |
651 |
|
|
url = wxT("/") + url; |
652 |
|
|
#endif |
653 |
|
|
|
654 |
|
|
} |
655 |
|
|
#endif |
656 |
|
|
|
657 |
|
|
url.Replace(g_nativePathString, g_unixPathString); |
658 |
|
|
url.Replace(wxT("%"), wxT("%25")); // '%'s must be replaced first! |
659 |
|
|
url.Replace(wxT("#"), wxT("%23")); |
660 |
|
|
url.Replace(wxT(":"), wxT("%3A")); |
661 |
|
|
url = wxT("file:") + url; |
662 |
|
|
return url; |
663 |
|
|
} |
664 |
|
|
|
665 |
|
|
|
666 |
|
|
///// Module: |
667 |
|
|
|
668 |
|
|
class wxFileSystemModule : public wxModule |
669 |
|
|
{ |
670 |
|
|
DECLARE_DYNAMIC_CLASS(wxFileSystemModule) |
671 |
|
|
|
672 |
|
|
public: |
673 |
|
|
wxFileSystemModule() : |
674 |
|
|
wxModule(), |
675 |
|
|
m_handler(NULL) |
676 |
|
|
{ |
677 |
|
|
} |
678 |
|
|
|
679 |
|
|
virtual bool OnInit() |
680 |
|
|
{ |
681 |
|
|
m_handler = new wxLocalFSHandler; |
682 |
|
|
wxFileSystem::AddHandler(m_handler); |
683 |
|
|
return true; |
684 |
|
|
} |
685 |
|
|
virtual void OnExit() |
686 |
|
|
{ |
687 |
|
|
delete wxFileSystem::RemoveHandler(m_handler); |
688 |
|
|
|
689 |
|
|
wxFileSystem::CleanUpHandlers(); |
690 |
|
|
} |
691 |
|
|
|
692 |
|
|
private: |
693 |
|
|
wxFileSystemHandler* m_handler; |
694 |
|
|
|
695 |
|
|
}; |
696 |
|
|
|
697 |
|
|
IMPLEMENT_DYNAMIC_CLASS(wxFileSystemModule, wxModule) |
698 |
|
|
|
699 |
|
|
#endif |
700 |
|
|
// wxUSE_FILESYSTEM |