debian: fix build-deps for focal
[amule.git] / src / libs / common / FileFunctions.cpp
blobb8f367cee6870581903b38b6bee5f2e00cfafe71
1 //
2 // This file is part of the aMule Project.
3 //
4 // Copyright (c) 2003-2011 aMule Team ( admin@amule.org / http://www.amule.org )
5 // Copyright (c) 2002-2011 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.
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 <algorithm> // Needed for std::min
39 #include "FileFunctions.h"
40 #include "StringFunctions.h"
41 #include "SmartPtr.h" // Needed for CSmartPtr
44 // This class assumes that the following line has been executed:
46 // wxConvFileName = &aMuleConvBrokenFileNames;
48 // This line is necessary so that wxWidgets handles unix file names correctly.
50 CDirIterator::CDirIterator(const CPath& dir)
51 : wxDir(dir.GetRaw())
56 CDirIterator::~CDirIterator()
61 CPath CDirIterator::GetFirstFile(FileType type, const wxString& mask)
63 if (!IsOpened()) {
64 return CPath();
67 wxString fileName;
68 if (!GetFirst(&fileName, mask, type)) {
69 return CPath();
72 return CPath(fileName);
76 CPath CDirIterator::GetNextFile()
78 wxString fileName;
79 if (!GetNext(&fileName)) {
80 return CPath();
83 return CPath(fileName);
87 bool CDirIterator::HasSubDirs(const wxString& spec)
89 // Checking IsOpened() in case we don't have permissions to read that dir.
90 return IsOpened() && wxDir::HasSubDirs(spec);
94 static EFileType GuessFiletype(const wxString& file)
96 wxFile archive(file, wxFile::read);
97 if (!archive.IsOpened()) {
98 return EFT_Error;
100 static const uint8 UTF8bom[3] = {0xEF, 0xBB, 0xBF};
101 uint8 head[10] = {0, 0};
102 int read = archive.Read(head, std::min<off_t>(10, archive.Length()));
104 if (read == wxInvalidOffset || read == 0) {
105 return EFT_Unknown;
106 } else if ((head[0] == 'P') && (head[1] == 'K')) {
107 // Zip-archives have a header of "PK".
108 return EFT_Zip;
109 } else if (head[0] == 0x1F && head[1] == 0x8B) {
110 // Gzip-archives have a header of 0x1F8B
111 return EFT_GZip;
112 } else if (head[0] == 0xE0 || head[0] == 0x0E) {
113 // MET files have either of these headers
114 return EFT_Met;
117 // Check at most the first ten chars, if all are printable,
118 // then we can probably assume it is ascii text-file.
119 for (int i = 0; i < read; ++i) {
120 if (!( isprint(head[i])
121 || isspace(head[i])
122 || (i < 3 && head[i] == UTF8bom[i]))) {
123 return EFT_Unknown;
127 return EFT_Text;
132 * Replaces the zip-archive with "guarding.p2p" or "ipfilter.dat",
133 * if either of those files are found in the archive.
135 static bool UnpackZipFile(const wxString& file, const wxChar* files[])
137 wxTempFile target(file);
138 CSmartPtr<wxZipEntry> entry;
139 wxFFileInputStream fileInputStream(file);
140 wxZipInputStream zip(fileInputStream);
141 bool run = true;
142 while (run) {
143 entry.reset(zip.GetNextEntry());
144 if (entry.get() == NULL) {
145 break;
147 // access meta-data
148 wxString name = entry->GetName();
149 // We only care about the files specified in the array
150 // probably needed to weed out included nfos
151 for (int i = 0; run && files[i]; i++) {
152 if (name.CmpNoCase(files[i]) == 0) {
153 // we found the entry we want
154 // read 'zip' to access the entry's data
155 char buffer[10240];
156 while (!zip.Eof()) {
157 zip.Read(buffer, sizeof(buffer));
158 target.Write(buffer, zip.LastRead());
160 run = false;
165 if (target.Length()) {
166 target.Commit();
167 return true;
170 return false;
175 * Unpacks a GZip file and replaces the archive.
177 static bool UnpackGZipFile(const wxString& file)
179 wxTempFile target(file);
181 bool write = false;
183 #ifdef __WXMAC__
184 // AddDebugLogLineN( logFileIO, wxT("Reading gzip stream") );
186 gzFile inputFile = gzopen(filename2char(file), "rb");
187 if (inputFile != NULL) {
188 char buffer[10240];
189 write = true;
191 while (int bytesRead = gzread(inputFile, buffer, sizeof(buffer))) {
192 if (bytesRead > 0) {
193 // AddDebugLogLineN(logFileIO, CFormat(wxT("Read %u bytes")) % bytesRead);
194 target.Write(buffer, bytesRead);
195 } else if (bytesRead < 0) {
196 wxString errString;
197 int gzerrnum;
198 const char* gzerrstr = gzerror(inputFile, &gzerrnum);
199 if (gzerrnum == Z_ERRNO) {
200 errString = wxSysErrorMsg();
201 } else {
202 errString = wxString::FromAscii(gzerrstr);
205 // AddDebugLogLineN( logFileIO, wxT("Error reading gzip stream (") + errString + wxT(")") );
206 write = false;
207 break;
211 // AddDebugLogLineN( logFileIO, wxT("End reading gzip stream") );
212 gzclose(inputFile);
213 } else {
214 // AddDebugLogLineN( logFileIO, wxT("Error opening gzip file (") + wxString(wxSysErrorMsg()) + wxT(")") );
216 #else
218 // AddDebugLogLineN( logFileIO, wxT("Reading gzip stream") );
220 wxFileInputStream source(file);
221 wxZlibInputStream inputStream(source);
223 while (!inputStream.Eof()) {
224 char buffer[10240];
225 inputStream.Read(buffer, sizeof(buffer));
227 // AddDebugLogLineN(logFileIO, CFormat(wxT("Read %u bytes")) % inputStream.LastRead());
228 if (inputStream.LastRead()) {
229 target.Write(buffer, inputStream.LastRead());
230 } else {
231 break;
235 // AddDebugLogLineN( logFileIO, wxT("End reading gzip stream") );
237 write = inputStream.IsOk() || inputStream.Eof();
239 #endif
241 if (write) {
242 target.Commit();
243 // AddDebugLogLineN( logFileIO, wxT("Commited gzip stream") );
246 return write;
250 UnpackResult UnpackArchive(const CPath& path, const wxChar* files[])
252 const wxString file = path.GetRaw();
254 // Attempt to discover the filetype and uncompress
255 EFileType type = GuessFiletype(file);
256 switch (type) {
257 case EFT_Zip:
258 if (UnpackZipFile(file, files)) {
259 // Unpack nested archives if needed.
260 return UnpackResult(true, UnpackArchive(path, files).second);
261 } else {
262 return UnpackResult(false, EFT_Error);
265 case EFT_GZip:
266 if (UnpackGZipFile(file)) {
267 // Unpack nested archives if needed.
268 return UnpackResult(true, UnpackArchive(path, files).second);
269 } else {
270 return UnpackResult(false, EFT_Error);
273 default:
274 return UnpackResult(false, type);
277 // File_checked_for_headers