1 /////////////////////////////////////////////////////////////////////////////
2 // Name: webviewfilehandler.cpp
3 // Purpose: Custom handler for the file scheme to allow archive browsing
4 // Author: Steven Lamerton
6 // Copyright: (c) 2011 Steven Lamerton
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
15 #if defined(__BORLANDC__)
19 #include "wx/webviewfilehandler.h"
20 #include "wx/filesys.h"
21 #include "wx/tokenzr.h"
22 #include "wx/hashmap.h"
24 typedef wxStringToStringHashMap QueryMap
;
26 QueryMap
QueryStringToQueryMap(wxString query
)
30 if(query
.substr(0, 1) == "?")
31 query
= query
.substr(1);
33 wxStringTokenizer
tokenizer(query
, ";");
34 while(tokenizer
.HasMoreTokens())
36 wxString token
= tokenizer
.GetNextToken();
37 size_t pos
= token
.find('=');
38 map
[token
.substr(0, pos
)] = token
.substr(pos
+ 1);
43 wxString
QueryMapToQueryString(QueryMap map
)
47 QueryMap::iterator it
;
48 for(it
= map
.begin(); it
!= map
.end(); ++it
)
50 query
= query
+ it
->first
+ "=" + it
->second
+ ";";
54 return query
.substr(0, query
.length() - 1);
57 //Taken from wx/filesys.cpp
58 static wxString
EscapeFileNameCharsInURL(const char *in
)
62 for ( const unsigned char *p
= (const unsigned char*)in
; *p
; ++p
)
64 const unsigned char c
= *p
;
66 if ( c
== '/' || c
== '-' || c
== '.' || c
== '_' || c
== '~' ||
67 (c
>= '0' && c
<= '9') ||
68 (c
>= 'a' && c
<= 'z') ||
69 (c
>= 'A' && c
<= 'Z') )
75 s
<< wxString::Format("%%%02x", c
);
82 wxWebFileHandler::wxWebFileHandler()
85 m_fileSystem
= new wxFileSystem();
88 wxFSFile
* wxWebFileHandler::GetFile(const wxString
&uri
)
90 size_t pos
= uri
.find('?');
91 //There is no query string so we can load the file directly
92 if(pos
== wxString::npos
)
94 size_t doubleslash
= uri
.find("//");
95 //The path is incorrectly formed without // after the first protocol
96 if(doubleslash
== wxString::npos
)
99 wxString fspath
= "file:" +
100 EscapeFileNameCharsInURL(uri
.substr(doubleslash
+ 2));
101 return m_fileSystem
->OpenFile(fspath
);
103 //Otherwise we have a query string of some kind that we need to extract
105 wxString lefturi
= uri
.substr(0, pos
);
107 //We extract the query parts that we need
108 QueryMap map
= QueryStringToQueryMap(uri
.substr(pos
));
109 wxString protocol
= map
["protocol"], path
= map
["path"];
111 //We now have the path and the protocol and so can format a correct uri
112 //to pass to wxFileSystem to get a wxFSFile
113 size_t doubleslash
= uri
.find("//");
114 //The path is incorrectly formed without // after the first protocol
115 if(doubleslash
== wxString::npos
)
118 wxString fspath
= "file:" +
119 EscapeFileNameCharsInURL(lefturi
.substr(doubleslash
+ 2))
120 + "#" + protocol
+":" + path
;
121 return m_fileSystem
->OpenFile(fspath
);
125 wxString
wxWebFileHandler::CombineURIs(const wxString
&baseuri
,
126 const wxString
&newuri
)
128 //If there is a colon in the path then we just return it
129 if(newuri
.find(':') != wxString::npos
)
133 //We have an absolute path and no query string
134 else if(newuri
.substr(0, 1) == "/" && baseuri
.find('?') == wxString::npos
)
136 //By finding the next / after file:// we get to the end of the
137 //(optional) hostname
138 size_t pos
= baseuri
.find('/', 7);
139 //So we return up to the end of the hostname, plus the newuri
140 return baseuri
.substr(0, pos
) + newuri
;
142 //We have an absolute path and a query string
143 else if(newuri
.substr(0, 1) == "/" && baseuri
.find('?') != wxString::npos
)
145 QueryMap map
= QueryStringToQueryMap(baseuri
.substr(baseuri
.find('?')));
146 //As the path is absolue simply replace the old path with the new one
147 map
["path"] = newuri
;
148 wxString newquery
= QueryMapToQueryString(map
);
149 return baseuri
.substr(0, baseuri
.find('?')) + newquery
;
151 //We have a relative path and no query string
152 else if(baseuri
.find('?') == wxString::npos
)
154 //By finding the next / after file:// we get to the end of the
155 //(optional) hostname
156 size_t pos
= baseuri
.find('/', 7);
157 wxString path
= baseuri
.substr(pos
);
158 //Then we remove the last filename
159 path
= path
.BeforeLast('/') + '/';
161 //If we have a colon in the path (i.e. we are on windows) we need to
162 //handle it specially
163 if(path
.find(':') != wxString::npos
)
165 wxFileName
fn(path
.AfterFirst('/').AfterFirst('/') + newuri
);
166 fn
.Normalize(wxPATH_NORM_DOTS
, "", wxPATH_UNIX
);
167 return baseuri
.substr(0, pos
) + '/' +
168 path
.AfterFirst('/').BeforeFirst('/') + '/' +
169 fn
.GetFullPath(wxPATH_UNIX
);
173 //We can now use wxFileName to perform the normalisation
174 wxFileName
fn(path
+ newuri
);
175 fn
.Normalize(wxPATH_NORM_DOTS
, "", wxPATH_UNIX
);
176 return baseuri
.substr(0, pos
) + fn
.GetFullPath(wxPATH_UNIX
);
179 //We have a relative path and a query string
182 QueryMap map
= QueryStringToQueryMap(baseuri
.substr(baseuri
.find('?')));
183 wxString path
= map
["path"];
184 //Then we remove the last filename
185 path
= path
.BeforeLast('/') + '/';
187 //We can now use wxFileName to perform the normalisation
188 wxFileName
fn(path
+ newuri
);
189 fn
.Normalize(wxPATH_NORM_DOTS
, "", wxPATH_UNIX
);
190 map
["path"] = fn
.GetFullPath(wxPATH_UNIX
);
192 wxString newquery
= QueryMapToQueryString(map
);
193 return baseuri
.substr(0, baseuri
.find('?')) + newquery
;