]> git.saurik.com Git - wxWidgets.git/blob - src/common/fs_zip.cpp
f3e807d87c7d590cac1a80c4cd69135a25e5b9da
[wxWidgets.git] / src / common / fs_zip.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: fs_zip.cpp
3 // Purpose: ZIP file system
4 // Author: Vaclav Slavik
5 // Copyright: (c) 1999 Vaclav Slavik
6 // CVS-ID: $Id$
7 // Licence: wxWindows Licence
8 /////////////////////////////////////////////////////////////////////////////
9
10
11
12 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
13 #pragma implementation "fs_zip.h"
14 #endif
15
16 #include "wx/wxprec.h"
17
18 #ifdef __BORLANDC__
19 #pragma hdrstop
20 #endif
21
22 #if wxUSE_FILESYSTEM && wxUSE_FS_ZIP && wxUSE_ZIPSTREAM
23
24 #ifndef WXPRECOMP
25 #include "wx/intl.h"
26 #include "wx/log.h"
27 #endif
28
29 #include "wx/hashmap.h"
30 #include "wx/filesys.h"
31 #include "wx/zipstrm.h"
32 #include "wx/fs_zip.h"
33
34 /* Not the right solution (paths in makefiles) but... */
35 #ifdef __BORLANDC__
36 #include "../common/unzip.h"
37 #else
38 #include "unzip.h"
39 #endif
40
41 WX_DECLARE_HASH_MAP_WITH_DECL( long, long, wxIntegerHash, wxIntegerEqual,
42 wxLongToLongHashMap, class WXDLLIMPEXP_BASE );
43
44 //----------------------------------------------------------------------------
45 // wxZipFSHandler
46 //----------------------------------------------------------------------------
47
48
49
50 wxZipFSHandler::wxZipFSHandler() : wxFileSystemHandler()
51 {
52 m_Archive = NULL;
53 m_ZipFile = m_Pattern = m_BaseDir = wxEmptyString;
54 m_AllowDirs = m_AllowFiles = TRUE;
55 m_DirsFound = NULL;
56 }
57
58
59
60 wxZipFSHandler::~wxZipFSHandler()
61 {
62 if (m_Archive)
63 unzClose((unzFile)m_Archive);
64 if (m_DirsFound)
65 delete m_DirsFound;
66 }
67
68
69
70 bool wxZipFSHandler::CanOpen(const wxString& location)
71 {
72 wxString p = GetProtocol(location);
73 return (p == wxT("zip")) &&
74 (GetProtocol(GetLeftLocation(location)) == wxT("file"));
75 }
76
77
78
79
80 wxFSFile* wxZipFSHandler::OpenFile(wxFileSystem& WXUNUSED(fs), const wxString& location)
81 {
82 wxString right = GetRightLocation(location);
83 wxString left = GetLeftLocation(location);
84 wxInputStream *s;
85
86 if (GetProtocol(left) != wxT("file"))
87 {
88 wxLogError(_("ZIP handler currently supports only local files!"));
89 return NULL;
90 }
91
92 if (right.Contains(wxT("./")))
93 {
94 if (right.GetChar(0) != wxT('/')) right = wxT('/') + right;
95 wxFileName rightPart(right, wxPATH_UNIX);
96 rightPart.Normalize(wxPATH_NORM_DOTS, wxT("/"), wxPATH_UNIX);
97 right = rightPart.GetFullPath(wxPATH_UNIX);
98 }
99
100 if (right.GetChar(0) == wxT('/')) right = right.Mid(1);
101
102 wxFileName leftFilename = wxFileSystem::URLToFileName(left);
103
104 s = new wxZipInputStream(leftFilename.GetFullPath(), right);
105 if (s && s->IsOk() )
106 {
107 return new wxFSFile(s,
108 left + wxT("#zip:") + right,
109 GetMimeTypeFromExt(location),
110 GetAnchor(location)
111 #if wxUSE_DATETIME
112 , wxDateTime(wxFileModificationTime(left))
113 #endif // wxUSE_DATETIME
114 );
115 }
116
117 delete s;
118 return NULL;
119 }
120
121
122
123 wxString wxZipFSHandler::FindFirst(const wxString& spec, int flags)
124 {
125 wxString right = GetRightLocation(spec);
126 wxString left = GetLeftLocation(spec);
127
128 if (right.Last() == wxT('/')) right.RemoveLast();
129
130 if (m_Archive)
131 {
132 unzClose((unzFile)m_Archive);
133 m_Archive = NULL;
134 }
135
136 if (GetProtocol(left) != wxT("file"))
137 {
138 wxLogError(_("ZIP handler currently supports only local files!"));
139 return wxEmptyString;
140 }
141
142 switch (flags)
143 {
144 case wxFILE:
145 m_AllowDirs = FALSE, m_AllowFiles = TRUE; break;
146 case wxDIR:
147 m_AllowDirs = TRUE, m_AllowFiles = FALSE; break;
148 default:
149 m_AllowDirs = m_AllowFiles = TRUE; break;
150 }
151
152 m_ZipFile = left;
153 wxString nativename = wxFileSystem::URLToFileName(m_ZipFile).GetFullPath();
154 m_Archive = (void*) unzOpen(nativename.mb_str());
155 m_Pattern = right.AfterLast(wxT('/'));
156 m_BaseDir = right.BeforeLast(wxT('/'));
157
158 if (m_Archive)
159 {
160 if (unzGoToFirstFile((unzFile)m_Archive) != UNZ_OK)
161 {
162 unzClose((unzFile)m_Archive);
163 m_Archive = NULL;
164 }
165 else
166 {
167 if (m_AllowDirs)
168 {
169 delete m_DirsFound;
170 m_DirsFound = new wxLongToLongHashMap();
171 }
172 return DoFind();
173 }
174 }
175 return wxEmptyString;
176 }
177
178
179
180 wxString wxZipFSHandler::FindNext()
181 {
182 if (!m_Archive) return wxEmptyString;
183 return DoFind();
184 }
185
186
187
188 wxString wxZipFSHandler::DoFind()
189 {
190 static char namebuf[1024]; // char, not wxChar!
191 char *c;
192 wxString namestr, dir, filename;
193 wxString match = wxEmptyString;
194
195 while (match == wxEmptyString)
196 {
197 unzGetCurrentFileInfo((unzFile)m_Archive, NULL, namebuf, 1024, NULL, 0, NULL, 0);
198 for (c = namebuf; *c; c++) if (*c == '\\') *c = '/';
199 namestr = wxString::FromAscii( namebuf ); // TODO what encoding does ZIP use?
200
201 if (m_AllowDirs)
202 {
203 dir = namestr.BeforeLast(wxT('/'));
204 while (!dir.IsEmpty())
205 {
206 long key = 0;
207 for (size_t i = 0; i < dir.Length(); i++) key += (wxUChar)dir[i];
208 wxLongToLongHashMap::iterator it = m_DirsFound->find(key);
209 if (it == m_DirsFound->end())
210 {
211 m_DirsFound[key] = 1;
212 filename = dir.AfterLast(wxT('/'));
213 dir = dir.BeforeLast(wxT('/'));
214 if (!filename.IsEmpty() && m_BaseDir == dir &&
215 wxMatchWild(m_Pattern, filename, FALSE))
216 match = m_ZipFile + wxT("#zip:") + dir + wxT("/") + filename;
217 }
218 else
219 break; // already tranversed
220 }
221 }
222
223 filename = namestr.AfterLast(wxT('/'));
224 dir = namestr.BeforeLast(wxT('/'));
225 if (m_AllowFiles && !filename.IsEmpty() && m_BaseDir == dir &&
226 wxMatchWild(m_Pattern, filename, FALSE))
227 match = m_ZipFile + wxT("#zip:") + namestr;
228
229 if (unzGoToNextFile((unzFile)m_Archive) != UNZ_OK)
230 {
231 unzClose((unzFile)m_Archive);
232 m_Archive = NULL;
233 break;
234 }
235 }
236
237 return match;
238 }
239
240
241
242 #endif
243 //wxUSE_FILESYSTEM && wxUSE_FS_ZIP && wxUSE_ZIPSTREAM