2 // This file is part of the aMule Project.
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 )
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
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
35 #include <zlib.h> // Do_not_auto_remove
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
)
56 CDirIterator::~CDirIterator()
61 CPath
CDirIterator::GetFirstFile(FileType type
, const wxString
& mask
)
68 if (!GetFirst(&fileName
, mask
, type
)) {
72 return CPath(fileName
);
76 CPath
CDirIterator::GetNextFile()
79 if (!GetNext(&fileName
)) {
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()) {
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) {
106 } else if ((head
[0] == 'P') && (head
[1] == 'K')) {
107 // Zip-archives have a header of "PK".
109 } else if (head
[0] == 0x1F && head
[1] == 0x8B) {
110 // Gzip-archives have a header of 0x1F8B
112 } else if (head
[0] == 0xE0 || head
[0] == 0x0E) {
113 // MET files have either of these headers
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
])
122 || (i
< 3 && head
[i
] == UTF8bom
[i
]))) {
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
);
143 entry
.reset(zip
.GetNextEntry());
144 if (entry
.get() == NULL
) {
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
157 zip
.Read(buffer
, sizeof(buffer
));
158 target
.Write(buffer
, zip
.LastRead());
165 if (target
.Length()) {
175 * Unpacks a GZip file and replaces the archive.
177 static bool UnpackGZipFile(const wxString
& file
)
179 wxTempFile
target(file
);
184 // AddDebugLogLineN( logFileIO, wxT("Reading gzip stream") );
186 gzFile inputFile
= gzopen(filename2char(file
), "rb");
187 if (inputFile
!= NULL
) {
191 while (int bytesRead
= gzread(inputFile
, buffer
, sizeof(buffer
))) {
193 // AddDebugLogLineN(logFileIO, CFormat(wxT("Read %u bytes")) % bytesRead);
194 target
.Write(buffer
, bytesRead
);
195 } else if (bytesRead
< 0) {
198 const char* gzerrstr
= gzerror(inputFile
, &gzerrnum
);
199 if (gzerrnum
== Z_ERRNO
) {
200 errString
= wxSysErrorMsg();
202 errString
= wxString::FromAscii(gzerrstr
);
205 // AddDebugLogLineN( logFileIO, wxT("Error reading gzip stream (") + errString + wxT(")") );
211 // AddDebugLogLineN( logFileIO, wxT("End reading gzip stream") );
214 // AddDebugLogLineN( logFileIO, wxT("Error opening gzip file (") + wxString(wxSysErrorMsg()) + wxT(")") );
218 // AddDebugLogLineN( logFileIO, wxT("Reading gzip stream") );
220 wxFileInputStream
source(file
);
221 wxZlibInputStream
inputStream(source
);
223 while (!inputStream
.Eof()) {
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());
235 // AddDebugLogLineN( logFileIO, wxT("End reading gzip stream") );
237 write
= inputStream
.IsOk() || inputStream
.Eof();
243 // AddDebugLogLineN( logFileIO, wxT("Commited gzip stream") );
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
);
258 if (UnpackZipFile(file
, files
)) {
259 // Unpack nested archives if needed.
260 return UnpackResult(true, UnpackArchive(path
, files
).second
);
262 return UnpackResult(false, EFT_Error
);
266 if (UnpackGZipFile(file
)) {
267 // Unpack nested archives if needed.
268 return UnpackResult(true, UnpackArchive(path
, files
).second
);
270 return UnpackResult(false, EFT_Error
);
274 return UnpackResult(false, type
);
277 // File_checked_for_headers