Upstream tarball 10106
[amule.git] / src / libs / common / FileFunctions.cpp
blobfd1af2a5bb9c8fb8b4d6c56ba438af59762d4937
1 //
2 // This file is part of the aMule Project.
3 //
4 // Copyright (c) 2003-2008 aMule Team ( admin@amule.org / http://www.amule.org )
5 // Copyright (c) 2002-2008 Merkur ( devs@emule-project.net / http://www.emule-project.net )
6 //
7 // Any parts of this program derived from the xMule, lMule or eMule project,
8 // or contributed by third-party developers are copyrighted by their
9 // respective authors.
11 // This program is free software; you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation; either version 2 of the License, or
14 // (at your option) any later version.
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU General Public License for more details.
20 //
21 // You should have received a copy of the GNU General Public License
22 // along with this program; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include <wx/dir.h> // Needed for wxDir
28 #include <wx/fs_zip.h> // Needed for wxZipFSHandler
29 #include <wx/wfstream.h> // wxFileInputStream
30 #include <wx/zipstrm.h> // Needed for wxZipInputStream
31 #include <wx/zstream.h> // Needed for wxZlibInputStream
32 #include <wx/log.h> // Needed for wxSysErrorMsg
34 #ifdef __WXMAC__
35 #include <zlib.h> // Do_not_auto_remove
36 #endif
37 #include <memory> // Needed for std::auto_ptr
39 #include "FileFunctions.h"
40 #include "StringFunctions.h"
43 // This class assumes that the following line has been executed:
45 // wxConvFileName = &aMuleConvBrokenFileNames;
47 // This line is necessary so that wxWidgets handles unix file names correctly.
49 CDirIterator::CDirIterator(const CPath& dir)
50 : wxDir(dir.GetRaw())
55 CDirIterator::~CDirIterator()
60 CPath CDirIterator::GetFirstFile(FileType type, const wxString& mask)
62 if (!IsOpened()) {
63 return CPath();
66 wxString fileName;
67 if (!GetFirst(&fileName, mask, type)) {
68 return CPath();
71 return CPath(fileName);
75 CPath CDirIterator::GetNextFile()
77 wxString fileName;
78 if (!GetNext(&fileName)) {
79 return CPath();
82 return CPath(fileName);
86 bool CDirIterator::HasSubDirs(const wxString& spec)
88 // Checking IsOpened() in case we don't have permissions to read that dir.
89 return IsOpened() && wxDir::HasSubDirs(spec);
93 EFileType GuessFiletype(const wxString& file)
95 wxFile archive(file, wxFile::read);
96 if (!archive.IsOpened()) {
97 return EFT_Error;
99 static const uint8 UTF8bom[3] = {0xEF, 0xBB, 0xBF};
100 uint8 head[10] = {0, 0};
101 int read = archive.Read(head, std::min<off_t>(10, archive.Length()));
103 if (read == wxInvalidOffset || read == 0) {
104 return EFT_Unknown;
105 } else if ((head[0] == 'P') && (head[1] == 'K')) {
106 // Zip-archives have a header of "PK".
107 return EFT_Zip;
108 } else if (head[0] == 0x1F && head[1] == 0x8B) {
109 // Gzip-archives have a header of 0x1F8B
110 return EFT_GZip;
111 } else if (head[0] == 0xE0 || head[0] == 0x0E) {
112 // MET files have either of these headers
113 return EFT_Met;
116 // Check at most the first ten chars, if all are printable,
117 // then we can probably assume it is ascii text-file.
118 for (int i = 0; i < read; ++i) {
119 if (!( isprint(head[i])
120 || isspace(head[i])
121 || (i < 3 && head[i] == UTF8bom[i]))) {
122 return EFT_Unknown;
126 return EFT_Text;
131 * Replaces the zip-archive with "guarding.p2p" or "ipfilter.dat",
132 * if either of those files are found in the archive.
134 bool UnpackZipFile(const wxString& file, const wxChar* files[])
136 wxZipFSHandler archive;
137 wxString filename = archive.FindFirst(
138 wxT("file:") + file + wxT("#zip:/*"), wxFILE);
140 wxTempFile target(file);
142 while (!filename.IsEmpty() && !target.Length()) {
143 // Extract the filename part of the URI
144 filename = filename.AfterLast(wxT(':')).Lower();
146 // We only care about the files specified in the array
147 for (size_t i = 0; files[i] && !target.Length(); ++i) {
148 if (files[i] == filename) {
149 std::auto_ptr<wxZipEntry> entry;
150 wxFFileInputStream fileInputStream(file);
151 wxZipInputStream zip(fileInputStream);
152 while (entry.reset(zip.GetNextEntry()), entry.get() != NULL) {
153 // access meta-data
154 wxString name = entry->GetName();
155 // read 'zip' to access the entry's data
156 if (name == filename) {
157 char buffer[10240];
158 while (!zip.Eof()) {
159 zip.Read(buffer, sizeof(buffer));
160 target.Write(buffer, zip.LastRead());
162 break;
168 filename = archive.FindNext();
171 if (target.Length()) {
172 target.Commit();
173 return true;
176 return false;
181 * Unpacks a GZip file and replaces the archive.
183 bool UnpackGZipFile(const wxString& file)
185 char buffer[10240];
186 wxTempFile target(file);
188 bool write = false;
190 #ifdef __WXMAC__
191 // AddDebugLogLineM( false, logFileIO, wxT("Reading gzip stream") );
193 gzFile inputFile = gzopen(filename2char(file), "rb");
194 if (inputFile != NULL) {
195 write = true;
197 while (int bytesRead = gzread(inputFile, buffer, sizeof(buffer))) {
198 if (bytesRead > 0) {
199 // AddDebugLogLineM( false, logFileIO, wxString::Format(wxT("Read %u bytes"), bytesRead) );
200 target.Write(buffer, bytesRead);
201 } else if (bytesRead < 0) {
202 wxString errString;
203 int gzerrnum;
204 const char* gzerrstr = gzerror(inputFile, &gzerrnum);
205 if (gzerrnum == Z_ERRNO) {
206 errString = wxSysErrorMsg();
207 } else {
208 errString = wxString::FromAscii(gzerrstr);
211 // AddDebugLogLineM( false, logFileIO, wxT("Error reading gzip stream (") + errString + wxT(")") );
212 write = false;
213 break;
217 // AddDebugLogLineM( false, logFileIO, wxT("End reading gzip stream") );
218 gzclose(inputFile);
219 } else {
220 // AddDebugLogLineM( false, logFileIO, wxT("Error opening gzip file (") + wxString(wxSysErrorMsg()) + wxT(")") );
222 #else
224 // AddDebugLogLineM( false, logFileIO, wxT("Reading gzip stream") );
226 wxFileInputStream source(file);
227 wxZlibInputStream inputStream(source);
229 while (!inputStream.Eof()) {
230 inputStream.Read(buffer, sizeof(buffer));
232 // AddDebugLogLineM( false, logFileIO, wxString::Format(wxT("Read %u bytes"),inputStream.LastRead()) );
233 if (inputStream.LastRead()) {
234 target.Write(buffer, inputStream.LastRead());
235 } else {
236 break;
240 // AddDebugLogLineM( false, logFileIO, wxT("End reading gzip stream") );
242 write = inputStream.IsOk() || inputStream.Eof();
244 #endif
246 if (write) {
247 target.Commit();
248 // AddDebugLogLineM( false, logFileIO, wxT("Commited gzip stream") );
251 return write;
255 UnpackResult UnpackArchive(const CPath& path, const wxChar* files[])
257 const wxString file = path.GetRaw();
259 // Attempt to discover the filetype and uncompress
260 EFileType type = GuessFiletype(file);
261 switch (type) {
262 case EFT_Zip:
263 if (UnpackZipFile(file, files)) {
264 // Unpack nested archives if needed.
265 return UnpackResult(true, UnpackArchive(path, files).second);
266 } else {
267 return UnpackResult(false, EFT_Error);
270 case EFT_GZip:
271 if (UnpackGZipFile(file)) {
272 // Unpack nested archives if needed.
273 return UnpackResult(true, UnpackArchive(path, files).second);
274 } else {
275 return UnpackResult(false, EFT_Error);
278 default:
279 return UnpackResult(false, type);
282 // File_checked_for_headers