]> git.saurik.com Git - wxWidgets.git/blame - src/common/filesys.cpp
Make public headers compatible with Objective-C++ with ARC.
[wxWidgets.git] / src / common / filesys.cpp
CommitLineData
5526e819 1/////////////////////////////////////////////////////////////////////////////
e4db172a 2// Name: src/common/filesys.cpp
5526e819
VS
3// Purpose: wxFileSystem class - interface for opening files
4// Author: Vaclav Slavik
5// Copyright: (c) 1999 Vaclav Slavik
65571936 6// Licence: wxWindows licence
5526e819
VS
7/////////////////////////////////////////////////////////////////////////////
8
d30e0edd 9#include "wx/wxprec.h"
5526e819 10
2b5f62a0 11#ifdef __BORLANDC__
e4db172a 12 #pragma hdrstop
5526e819
VS
13#endif
14
31528cd3 15
24528b0c 16#if wxUSE_FILESYSTEM
5526e819 17
e4db172a
WS
18#include "wx/filesys.h"
19
20#ifndef WX_PRECOMP
21 #include "wx/log.h"
02761f6c 22 #include "wx/module.h"
e4db172a
WS
23#endif
24
c895624b 25#include "wx/sysopt.h"
d30e0edd 26#include "wx/wfstream.h"
73725567 27#include "wx/mimetype.h"
6464f4cb 28#include "wx/filename.h"
3ab6fcee 29#include "wx/tokenzr.h"
d81f6eac 30#include "wx/uri.h"
916af76f 31#include "wx/private/fileback.h"
73725567 32
69cce151
VS
33// ----------------------------------------------------------------------------
34// wxFSFile
35// ----------------------------------------------------------------------------
73725567 36
69cce151
VS
37const wxString& wxFSFile::GetMimeType() const
38{
39 if ( m_MimeType.empty() && !m_Location.empty() )
40 {
41 wxConstCast(this, wxFSFile)->m_MimeType =
42 wxFileSystemHandler::GetMimeTypeFromExt(m_Location);
43 }
44
45 return m_MimeType;
46}
47
48// ----------------------------------------------------------------------------
5526e819 49// wxFileSystemHandler
69cce151 50// ----------------------------------------------------------------------------
5526e819
VS
51
52IMPLEMENT_ABSTRACT_CLASS(wxFileSystemHandler, wxObject)
53
5526e819 54
69cce151 55/* static */
5526e819
VS
56wxString wxFileSystemHandler::GetMimeTypeFromExt(const wxString& location)
57{
45681cd7 58 wxString ext, mime;
5526e819 59 wxString loc = GetRightLocation(location);
53b99810 60 wxChar c;
e4db172a 61 int l = loc.length(), l2;
5526e819
VS
62
63 l2 = l;
46837272 64 for (int i = l-1; i >= 0; i--)
45681cd7 65 {
ea4f5235 66 c = loc[(unsigned int) i];
45681cd7
VS
67 if ( c == wxT('#') )
68 l2 = i + 1;
69 if ( c == wxT('.') )
70 {
46837272 71 ext = loc.Right(l2-i-1);
45681cd7
VS
72 break;
73 }
74 if ( (c == wxT('/')) || (c == wxT('\\')) || (c == wxT(':')) )
75 return wxEmptyString;
5526e819 76 }
956418ab 77
45681cd7 78#if wxUSE_MIMETYPE
121680bf 79 static bool s_MinimalMimeEnsured = false;
c895624b
JS
80
81 // Don't use mime types manager if the application doesn't need it and it would be
82 // cause an unacceptable delay, especially on startup.
c895624b 83#if wxUSE_SYSTEM_OPTIONS
107b52ed 84 if ( !wxSystemOptions::GetOptionInt(wxT("filesys.no-mimetypesmanager")) )
c895624b 85#endif
121680bf 86 {
c895624b 87 if (!s_MinimalMimeEnsured)
121680bf 88 {
c895624b
JS
89 static const wxFileTypeInfo fallbacks[] =
90 {
9a83f860 91 wxFileTypeInfo(wxT("image/jpeg"),
c895624b
JS
92 wxEmptyString,
93 wxEmptyString,
9a83f860
VZ
94 wxT("JPEG image (from fallback)"),
95 wxT("jpg"), wxT("jpeg"), wxT("JPG"), wxT("JPEG"), wxNullPtr),
96 wxFileTypeInfo(wxT("image/gif"),
c895624b
JS
97 wxEmptyString,
98 wxEmptyString,
9a83f860
VZ
99 wxT("GIF image (from fallback)"),
100 wxT("gif"), wxT("GIF"), wxNullPtr),
101 wxFileTypeInfo(wxT("image/png"),
c895624b
JS
102 wxEmptyString,
103 wxEmptyString,
9a83f860
VZ
104 wxT("PNG image (from fallback)"),
105 wxT("png"), wxT("PNG"), wxNullPtr),
106 wxFileTypeInfo(wxT("image/bmp"),
c895624b
JS
107 wxEmptyString,
108 wxEmptyString,
9a83f860
VZ
109 wxT("windows bitmap image (from fallback)"),
110 wxT("bmp"), wxT("BMP"), wxNullPtr),
111 wxFileTypeInfo(wxT("text/html"),
c895624b
JS
112 wxEmptyString,
113 wxEmptyString,
9a83f860
VZ
114 wxT("HTML document (from fallback)"),
115 wxT("htm"), wxT("html"), wxT("HTM"), wxT("HTML"), wxNullPtr),
44d0f703
VS
116 // must terminate the table with this!
117 wxFileTypeInfo()
c895624b
JS
118 };
119 wxTheMimeTypesManager->AddFallbacks(fallbacks);
120 s_MinimalMimeEnsured = true;
121 }
03647350 122
c895624b
JS
123 wxFileType *ft = wxTheMimeTypesManager->GetFileTypeFromExtension(ext);
124 if ( !ft || !ft -> GetMimeType(&mime) )
125 {
126 mime = wxEmptyString;
127 }
03647350 128
c895624b 129 delete ft;
03647350 130
c895624b 131 return mime;
956418ab 132 }
c895624b
JS
133 else
134#endif
45681cd7 135 {
9a83f860 136 if ( ext.IsSameAs(wxT("htm"), false) || ext.IsSameAs(wxT("html"), false) )
c895624b 137 return wxT("text/html");
9a83f860 138 if ( ext.IsSameAs(wxT("jpg"), false) || ext.IsSameAs(wxT("jpeg"), false) )
c895624b
JS
139 return wxT("image/jpeg");
140 if ( ext.IsSameAs(wxT("gif"), false) )
141 return wxT("image/gif");
142 if ( ext.IsSameAs(wxT("png"), false) )
143 return wxT("image/png");
144 if ( ext.IsSameAs(wxT("bmp"), false) )
145 return wxT("image/bmp");
146 return wxEmptyString;
51f79d5c 147 }
5526e819
VS
148}
149
150
151
69cce151
VS
152/* static */
153wxString wxFileSystemHandler::GetProtocol(const wxString& location)
5526e819
VS
154{
155 wxString s = wxEmptyString;
e4db172a 156 int i, l = location.length();
a62848fd 157 bool fnd = false;
5526e819 158
223d09f6 159 for (i = l-1; (i >= 0) && ((location[i] != wxT('#')) || (!fnd)); i--) {
a62848fd 160 if ((location[i] == wxT(':')) && (i != 1 /*win: C:\path*/)) fnd = true;
5526e819 161 }
223d09f6
KB
162 if (!fnd) return wxT("file");
163 for (++i; (i < l) && (location[i] != wxT(':')); i++) s << location[i];
5526e819
VS
164 return s;
165}
166
167
69cce151
VS
168/* static */
169wxString wxFileSystemHandler::GetLeftLocation(const wxString& location)
5526e819
VS
170{
171 int i;
a62848fd 172 bool fnd = false;
5526e819 173
e4db172a 174 for (i = location.length()-1; i >= 0; i--) {
a62848fd 175 if ((location[i] == wxT(':')) && (i != 1 /*win: C:\path*/)) fnd = true;
223d09f6 176 else if (fnd && (location[i] == wxT('#'))) return location.Left(i);
5526e819
VS
177 }
178 return wxEmptyString;
179}
180
69cce151
VS
181/* static */
182wxString wxFileSystemHandler::GetRightLocation(const wxString& location)
5526e819 183{
e4db172a 184 int i, l = location.length();
5526e819 185 int l2 = l + 1;
008a56c9 186
a62848fd
WS
187 for (i = l-1;
188 (i >= 0) &&
f8ae31dc 189 ((location[i] != wxT(':')) || (i == 1) || (location[i-2] == wxT(':')));
008a56c9 190 i--)
c8c29c49
JS
191 {
192 if (location[i] == wxT('#')) l2 = i + 1;
193 }
5526e819
VS
194 if (i == 0) return wxEmptyString;
195 else return location.Mid(i + 1, l2 - i - 2);
196}
197
69cce151
VS
198/* static */
199wxString wxFileSystemHandler::GetAnchor(const wxString& location)
5526e819 200{
53b99810 201 wxChar c;
e4db172a 202 int l = location.length();
5526e819
VS
203
204 for (int i = l-1; i >= 0; i--) {
205 c = location[i];
91915e1c
VS
206 if (c == wxT('#'))
207 return location.Right(l-i-1);
208 else if ((c == wxT('/')) || (c == wxT('\\')) || (c == wxT(':')))
209 return wxEmptyString;
5526e819
VS
210 }
211 return wxEmptyString;
212}
213
aaa66113 214
f76dbc4d
VZ
215wxString wxFileSystemHandler::FindFirst(const wxString& WXUNUSED(spec),
216 int WXUNUSED(flags))
217{
218 return wxEmptyString;
219}
aaa66113 220
f76dbc4d
VZ
221wxString wxFileSystemHandler::FindNext()
222{
223 return wxEmptyString;
224}
aaa66113 225
5526e819
VS
226//--------------------------------------------------------------------------------
227// wxLocalFSHandler
228//--------------------------------------------------------------------------------
229
5526e819 230
19008b7b 231wxString wxLocalFSHandler::ms_root;
5526e819 232
5526e819
VS
233bool wxLocalFSHandler::CanOpen(const wxString& location)
234{
223d09f6 235 return GetProtocol(location) == wxT("file");
5526e819
VS
236}
237
5526e819
VS
238wxFSFile* wxLocalFSHandler::OpenFile(wxFileSystem& WXUNUSED(fs), const wxString& location)
239{
6464f4cb 240 // location has Unix path separators
008a56c9 241 wxString right = GetRightLocation(location);
9548c49a 242 wxFileName fn = wxFileSystem::URLToFileName(right);
008a56c9 243 wxString fullpath = ms_root + fn.GetFullPath();
46837272 244
008a56c9 245 if (!wxFileExists(fullpath))
d3b9f782 246 return NULL;
46837272 247
3e5175b7
VZ
248 // we need to check whether we can really read from this file, otherwise
249 // wxFSFile is not going to work
8d6c5e4f 250#if wxUSE_FFILE
3e5175b7 251 wxFFileInputStream *is = new wxFFileInputStream(fullpath);
8d6c5e4f
VS
252#elif wxUSE_FILE
253 wxFileInputStream *is = new wxFileInputStream(fullpath);
d9b0ee1e
VZ
254#else
255#error One of wxUSE_FILE or wxUSE_FFILE must be set to 1 for wxFSHandler to work
256#endif
a1b806b9 257 if ( !is->IsOk() )
3e5175b7
VZ
258 {
259 delete is;
d3b9f782 260 return NULL;
3e5175b7
VZ
261 }
262
263 return new wxFSFile(is,
4d4e7a8a 264 location,
69cce151 265 wxEmptyString,
e2b87f38
VZ
266 GetAnchor(location)
267#if wxUSE_DATETIME
268 ,wxDateTime(wxFileModificationTime(fullpath))
269#endif // wxUSE_DATETIME
270 );
5526e819
VS
271}
272
aaa66113
VS
273wxString wxLocalFSHandler::FindFirst(const wxString& spec, int flags)
274{
008a56c9 275 wxFileName fn = wxFileSystem::URLToFileName(GetRightLocation(spec));
8e63b7b8
VS
276 const wxString found = wxFindFirstFile(ms_root + fn.GetFullPath(), flags);
277 if ( found.empty() )
278 return found;
279 return wxFileSystem::FileNameToURL(found);
aaa66113
VS
280}
281
282wxString wxLocalFSHandler::FindNext()
283{
8e63b7b8
VS
284 const wxString found = wxFindNextFile();
285 if ( found.empty() )
286 return found;
287 return wxFileSystem::FileNameToURL(found);
aaa66113
VS
288}
289
290
291
5526e819
VS
292//-----------------------------------------------------------------------------
293// wxFileSystem
294//-----------------------------------------------------------------------------
295
296IMPLEMENT_DYNAMIC_CLASS(wxFileSystem, wxObject)
46837272 297IMPLEMENT_ABSTRACT_CLASS(wxFSFile, wxObject)
5526e819
VS
298
299
300wxList wxFileSystem::m_Handlers;
301
302
52ad298e
MW
303wxFileSystem::~wxFileSystem()
304{
305 WX_CLEAR_HASH_MAP(wxFSHandlerHash, m_LocalHandlers)
306}
307
308
5be0cf65
VS
309static wxString MakeCorrectPath(const wxString& path)
310{
311 wxString p(path);
312 wxString r;
313 int i, j, cnt;
86b3203f 314
e4db172a 315 cnt = p.length();
5be0cf65 316 for (i = 0; i < cnt; i++)
f6081a04 317 if (p.GetChar(i) == wxT('\\')) p.GetWritableChar(i) = wxT('/'); // Want to be windows-safe
86b3203f 318
5be0cf65 319 if (p.Left(2) == wxT("./")) { p = p.Mid(2); cnt -= 2; }
86b3203f 320
5be0cf65 321 if (cnt < 3) return p;
86b3203f 322
b2f60e03 323 r << p.GetChar(0) << p.GetChar(1);
86b3203f 324
5be0cf65 325 // skip trailing ../.., if any
b2f60e03 326 for (i = 2; i < cnt && (p.GetChar(i) == wxT('/') || p.GetChar(i) == wxT('.')); i++) r << p.GetChar(i);
86b3203f 327
5be0cf65
VS
328 // remove back references: translate dir1/../dir2 to dir2
329 for (; i < cnt; i++)
330 {
b2f60e03
BJ
331 r << p.GetChar(i);
332 if (p.GetChar(i) == wxT('/') && p.GetChar(i-1) == wxT('.') && p.GetChar(i-2) == wxT('.'))
5be0cf65 333 {
e4db172a 334 for (j = r.length() - 2; j >= 0 && r.GetChar(j) != wxT('/') && r.GetChar(j) != wxT(':'); j--) {}
b2f60e03 335 if (j >= 0 && r.GetChar(j) != wxT(':'))
5be0cf65 336 {
b2f60e03 337 for (j = j - 1; j >= 0 && r.GetChar(j) != wxT('/') && r.GetChar(j) != wxT(':'); j--) {}
5be0cf65
VS
338 r.Remove(j + 1);
339 }
340 }
341 }
86b3203f 342
b2f60e03 343 for (; i < cnt; i++) r << p.GetChar(i);
86b3203f 344
5be0cf65
VS
345 return r;
346}
347
5526e819
VS
348
349void wxFileSystem::ChangePathTo(const wxString& location, bool is_dir)
350{
351 int i, pathpos = -1;
5526e819 352
5be0cf65 353 m_Path = MakeCorrectPath(location);
d30e0edd 354
aaa66113
VS
355 if (is_dir)
356 {
6636ef8d 357 if (!m_Path.empty() && m_Path.Last() != wxT('/') && m_Path.Last() != wxT(':'))
d81152f4 358 m_Path << wxT('/');
aaa66113 359 }
86b3203f 360
aaa66113 361 else
d30e0edd 362 {
e4db172a 363 for (i = m_Path.length()-1; i >= 0; i--)
d81152f4 364 {
223d09f6 365 if (m_Path[(unsigned int) i] == wxT('/'))
d81152f4 366 {
223d09f6 367 if ((i > 1) && (m_Path[(unsigned int) (i-1)] == wxT('/')) && (m_Path[(unsigned int) (i-2)] == wxT(':')))
d81152f4 368 {
5526e819
VS
369 i -= 2;
370 continue;
371 }
269e8200 372 else
d81152f4 373 {
269e8200 374 pathpos = i;
5526e819
VS
375 break;
376 }
377 }
aaa66113
VS
378 else if (m_Path[(unsigned int) i] == wxT(':')) {
379 pathpos = i;
380 break;
381 }
5526e819 382 }
269e8200 383 if (pathpos == -1)
d81152f4 384 {
e4db172a 385 for (i = 0; i < (int) m_Path.length(); i++)
d81152f4 386 {
223d09f6 387 if (m_Path[(unsigned int) i] == wxT(':'))
d81152f4 388 {
5526e819
VS
389 m_Path.Remove(i+1);
390 break;
391 }
392 }
e4db172a 393 if (i == (int) m_Path.length())
d81152f4 394 m_Path = wxEmptyString;
5526e819 395 }
269e8200 396 else
d81152f4 397 {
5526e819
VS
398 m_Path.Remove(pathpos+1);
399 }
400 }
401}
402
403
404
52ad298e
MW
405wxFileSystemHandler *wxFileSystem::MakeLocal(wxFileSystemHandler *h)
406{
407 wxClassInfo *classinfo = h->GetClassInfo();
408
409 if (classinfo->IsDynamic())
410 {
411 wxFileSystemHandler*& local = m_LocalHandlers[classinfo];
412 if (!local)
413 local = (wxFileSystemHandler*)classinfo->CreateObject();
414 return local;
415 }
416 else
417 {
418 return h;
419 }
420}
421
422
423
8c3dbc46 424wxFSFile* wxFileSystem::OpenFile(const wxString& location, int flags)
5526e819 425{
0ce98614
MW
426 if ((flags & wxFS_READ) == 0)
427 return NULL;
428
5be0cf65
VS
429 wxString loc = MakeCorrectPath(location);
430 unsigned i, ln;
53b99810 431 wxChar meta;
5526e819 432 wxFSFile *s = NULL;
df5168c4 433 wxList::compatibility_iterator node;
5526e819 434
e4db172a 435 ln = loc.length();
5526e819 436 meta = 0;
269e8200 437 for (i = 0; i < ln; i++)
d30e0edd 438 {
c9f78968 439 switch ( loc[i].GetValue() )
2148cce2 440 {
86b3203f 441 case wxT('/') : case wxT(':') : case wxT('#') :
2148cce2
VS
442 meta = loc[i];
443 break;
444 }
445 if (meta != 0) break;
5526e819
VS
446 }
447 m_LastName = wxEmptyString;
448
449 // try relative paths first :
223d09f6 450 if (meta != wxT(':'))
d30e0edd 451 {
5526e819 452 node = m_Handlers.GetFirst();
d30e0edd 453 while (node)
d81152f4 454 {
5526e819 455 wxFileSystemHandler *h = (wxFileSystemHandler*) node -> GetData();
7dee4b2b 456 if (h->CanOpen(m_Path + loc))
d81152f4 457 {
52ad298e 458 s = MakeLocal(h)->OpenFile(*this, m_Path + loc);
7dee4b2b 459 if (s) { m_LastName = m_Path + loc; break; }
5526e819 460 }
d30e0edd 461 node = node->GetNext();
5526e819
VS
462 }
463 }
464
465 // if failed, try absolute paths :
269e8200 466 if (s == NULL)
d30e0edd 467 {
5526e819 468 node = m_Handlers.GetFirst();
d30e0edd 469 while (node)
d81152f4 470 {
d30e0edd 471 wxFileSystemHandler *h = (wxFileSystemHandler*) node->GetData();
7dee4b2b 472 if (h->CanOpen(loc))
d81152f4 473 {
52ad298e 474 s = MakeLocal(h)->OpenFile(*this, loc);
7dee4b2b 475 if (s) { m_LastName = loc; break; }
5526e819 476 }
d30e0edd 477 node = node->GetNext();
5526e819
VS
478 }
479 }
8c3dbc46
MW
480
481 if (s && (flags & wxFS_SEEKABLE) != 0 && !s->GetStream()->IsSeekable())
482 {
483 wxBackedInputStream *stream;
484 stream = new wxBackedInputStream(s->DetachStream());
485 stream->FindLength();
486 s->SetStream(stream);
487 }
488
5526e819
VS
489 return (s);
490}
491
492
aaa66113
VS
493
494wxString wxFileSystem::FindFirst(const wxString& spec, int flags)
495{
df5168c4 496 wxList::compatibility_iterator node;
aaa66113 497 wxString spec2(spec);
86b3203f 498
aaa66113
VS
499 m_FindFileHandler = NULL;
500
e4db172a 501 for (int i = spec2.length()-1; i >= 0; i--)
f6081a04 502 if (spec2[(unsigned int) i] == wxT('\\')) spec2.GetWritableChar(i) = wxT('/'); // Want to be windows-safe
aaa66113
VS
503
504 node = m_Handlers.GetFirst();
505 while (node)
506 {
52ad298e
MW
507 wxFileSystemHandler *h = (wxFileSystemHandler*) node -> GetData();
508 if (h -> CanOpen(m_Path + spec2))
509 {
510 m_FindFileHandler = MakeLocal(h);
aaa66113 511 return m_FindFileHandler -> FindFirst(m_Path + spec2, flags);
52ad298e 512 }
aaa66113 513 node = node->GetNext();
86b3203f 514 }
aaa66113
VS
515
516 node = m_Handlers.GetFirst();
517 while (node)
518 {
52ad298e
MW
519 wxFileSystemHandler *h = (wxFileSystemHandler*) node -> GetData();
520 if (h -> CanOpen(spec2))
521 {
522 m_FindFileHandler = MakeLocal(h);
aaa66113 523 return m_FindFileHandler -> FindFirst(spec2, flags);
52ad298e 524 }
aaa66113 525 node = node->GetNext();
86b3203f
DW
526 }
527
528 return wxEmptyString;
aaa66113
VS
529}
530
531
532
533wxString wxFileSystem::FindNext()
534{
535 if (m_FindFileHandler == NULL) return wxEmptyString;
536 else return m_FindFileHandler -> FindNext();
537}
538
3ab6fcee 539bool wxFileSystem::FindFileInPath(wxString *pStr,
593177c5
VS
540 const wxString& path,
541 const wxString& basename)
3ab6fcee
VZ
542{
543 // we assume that it's not empty
593177c5 544 wxCHECK_MSG( !basename.empty(), false,
9a83f860 545 wxT("empty file name in wxFileSystem::FindFileInPath"));
3ab6fcee 546
593177c5 547 wxString name;
3ab6fcee 548 // skip path separator in the beginning of the file name if present
593177c5
VS
549 if ( wxIsPathSeparator(basename[0u]) )
550 name = basename.substr(1);
551 else
552 name = basename;
aaa66113 553
3ab6fcee
VZ
554 wxStringTokenizer tokenizer(path, wxPATH_SEP);
555 while ( tokenizer.HasMoreTokens() )
556 {
557 wxString strFile = tokenizer.GetNextToken();
558 if ( !wxEndsWithPathSeparator(strFile) )
559 strFile += wxFILE_SEP_PATH;
593177c5 560 strFile += name;
3ab6fcee
VZ
561
562 wxFSFile *file = OpenFile(strFile);
563 if ( file )
564 {
565 delete file;
566 *pStr = strFile;
567 return true;
568 }
569 }
570
571 return false;
572}
aaa66113 573
5526e819
VS
574void wxFileSystem::AddHandler(wxFileSystemHandler *handler)
575{
4948ebf3
VZ
576 // prepend the handler to the beginning of the list because handlers added
577 // last should have the highest priority to allow overriding them
374b4f1c 578 m_Handlers.Insert((size_t)0, handler);
5526e819
VS
579}
580
5949d307
RR
581wxFileSystemHandler* wxFileSystem::RemoveHandler(wxFileSystemHandler *handler)
582{
583 // if handler has already been removed (or deleted)
584 // we return NULL. This is by design in case
585 // CleanUpHandlers() is called before RemoveHandler
586 // is called, as we cannot control the order
587 // which modules are unloaded
588 if (!m_Handlers.DeleteObject(handler))
589 return NULL;
590
591 return handler;
592}
593
594
b8b37ced
VZ
595bool wxFileSystem::HasHandlerForPath(const wxString &location)
596{
597 for ( wxList::compatibility_iterator node = m_Handlers.GetFirst();
598 node; node = node->GetNext() )
599 {
600 wxFileSystemHandler *h = (wxFileSystemHandler*) node->GetData();
601 if (h->CanOpen(location))
602 return true;
603 }
604
605 return false;
606}
5526e819 607
269e8200
RD
608void wxFileSystem::CleanUpHandlers()
609{
df5168c4 610 WX_CLEAR_LIST(wxList, m_Handlers);
269e8200
RD
611}
612
60431236
WS
613static const wxString g_unixPathString(wxT("/"));
614static const wxString g_nativePathString(wxFILE_SEP_PATH);
5526e819 615
2b5f62a0 616// Returns the native path for a file URL
9548c49a 617wxFileName wxFileSystem::URLToFileName(const wxString& url)
2b5f62a0 618{
a62848fd 619 wxString path = url;
2b5f62a0 620
a62848fd
WS
621 if ( path.Find(wxT("file://")) == 0 )
622 {
623 path = path.Mid(7);
624 }
008a56c9 625 else if ( path.Find(wxT("file:")) == 0 )
a62848fd
WS
626 {
627 path = path.Mid(5);
628 }
629 // Remove preceding double slash on Mac Classic
d0200d9e
JS
630#if defined(__WXMAC__) && !defined(__UNIX__)
631 else if ( path.Find(wxT("//")) == 0 )
632 path = path.Mid(2);
633#endif
a62848fd 634
d81f6eac 635 path = wxURI::Unescape(path);
2b5f62a0 636
d98a58c5 637#ifdef __WINDOWS__
a62848fd 638 // file urls either start with a forward slash (local harddisk),
2b5f62a0
VZ
639 // otherwise they have a servername/sharename notation,
640 // which only exists on msw and corresponds to a unc
9b42a9ad 641 if ( path.length() > 1 && (path[0u] == wxT('/') && path [1u] != wxT('/')) )
a62848fd
WS
642 {
643 path = path.Mid(1);
644 }
645 else if ( (url.Find(wxT("file://")) == 0) &&
2b5f62a0 646 (path.Find(wxT('/')) != wxNOT_FOUND) &&
e4db172a 647 (path.length() > 1) && (path[1u] != wxT(':')) )
a62848fd
WS
648 {
649 path = wxT("//") + path;
650 }
2b5f62a0 651#endif
9b798c66 652
a62848fd 653 path.Replace(g_unixPathString, g_nativePathString);
2b5f62a0 654
a62848fd 655 return wxFileName(path, wxPATH_NATIVE);
2b5f62a0
VZ
656}
657
c707d82e
VS
658// Escapes non-ASCII and others characters in file: URL to be valid URLs
659static wxString EscapeFileNameCharsInURL(const char *in)
660{
661 wxString s;
662
663 for ( const unsigned char *p = (const unsigned char*)in; *p; ++p )
664 {
665 const unsigned char c = *p;
666
667 // notice that all colons *must* be encoded in the paths used by
668 // wxFileSystem even though this makes URLs produced by this method
669 // unusable with IE under Windows as it requires "file:///c:/foo.bar"
670 // and doesn't accept "file:///c%3a/foo.bar" -- but then we never made
671 // any guarantees about general suitability of the strings returned by
672 // this method, they must work with wxFileSystem only and not encoding
673 // the colon breaks handling of
674 // "http://wherever/whatever.zip#zip:filename.ext" URLs so we really
675 // can't do this without heavy changes to the parsing code here, in
676 // particular in GetRightLocation()
677
678 if ( c == '/' || c == '-' || c == '.' || c == '_' || c == '~' ||
679 (c >= '0' && c <= '9') ||
680 (c >= 'a' && c <= 'z') ||
681 (c >= 'A' && c <= 'Z') )
682 {
683 s << c;
684 }
685 else
686 {
687 s << wxString::Format("%%%02x", c);
688 }
689 }
690
691 return s;
692}
693
2b5f62a0 694// Returns the file URL for a native path
9548c49a 695wxString wxFileSystem::FileNameToURL(const wxFileName& filename)
2b5f62a0 696{
9548c49a
VS
697 wxFileName fn = filename;
698 fn.Normalize(wxPATH_NORM_DOTS | wxPATH_NORM_TILDE | wxPATH_NORM_ABSOLUTE);
699 wxString url = fn.GetFullPath(wxPATH_NATIVE);
9b798c66 700
2a5d3f57
JS
701#ifndef __UNIX__
702 // unc notation, wxMSW
a62848fd 703 if ( url.Find(wxT("\\\\")) == 0 )
9548c49a 704 {
60c315ca 705 url = wxT("//") + url.Mid(2);
9548c49a
VS
706 }
707 else
708 {
709 url = wxT("/") + url;
d0200d9e
JS
710#ifdef __WXMAC__
711 url = wxT("/") + url;
712#endif
713
9548c49a 714 }
2b5f62a0 715#endif
9b798c66 716
9548c49a 717 url.Replace(g_nativePathString, g_unixPathString);
55129143
VS
718
719 // Do wxURI- and common practice-compatible escaping: encode the string
720 // into UTF-8, then escape anything non-ASCII:
c707d82e 721 return wxT("file:") + EscapeFileNameCharsInURL(url.utf8_str());
2b5f62a0 722}
aaa66113
VS
723
724
5526e819
VS
725///// Module:
726
727class wxFileSystemModule : public wxModule
728{
729 DECLARE_DYNAMIC_CLASS(wxFileSystemModule)
730
731 public:
5949d307
RR
732 wxFileSystemModule() :
733 wxModule(),
734 m_handler(NULL)
735 {
736 }
737
5526e819
VS
738 virtual bool OnInit()
739 {
5949d307
RR
740 m_handler = new wxLocalFSHandler;
741 wxFileSystem::AddHandler(m_handler);
121680bf 742 return true;
5526e819 743 }
269e8200 744 virtual void OnExit()
d81152f4 745 {
5949d307
RR
746 delete wxFileSystem::RemoveHandler(m_handler);
747
269e8200 748 wxFileSystem::CleanUpHandlers();
d81152f4 749 }
5949d307
RR
750
751 private:
752 wxFileSystemHandler* m_handler;
753
5526e819
VS
754};
755
756IMPLEMENT_DYNAMIC_CLASS(wxFileSystemModule, wxModule)
757
b7775a52
VZ
758//// wxFSInputStream
759
760wxFSInputStream::wxFSInputStream(const wxString& filename, int flags)
761{
762 wxFileSystem fs;
763 m_file = fs.OpenFile(filename, flags | wxFS_READ);
764
765 if ( m_file )
766 {
767 wxInputStream* const stream = m_file->GetStream();
768 if ( stream )
769 {
770 // Notice that we pass the stream by reference: it shouldn't be
771 // deleted by us as it's owned by m_file already.
772 InitParentStream(*stream);
773 }
774 }
775}
776
777wxFSInputStream::~wxFSInputStream()
778{
779 delete m_file;
780}
781
269e8200 782#endif
24528b0c 783 // wxUSE_FILESYSTEM