// // This file is part of the aMule Project. // // Copyright (c) 2003-2011 aMule Team ( admin@amule.org / http://www.amule.org ) // Copyright (c) 2002-2011 Merkur ( devs@emule-project.net / http://www.emule-project.net ) // // Any parts of this program derived from the xMule, lMule or eMule project, // or contributed by third-party developers are copyrighted by their // respective authors. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA // #include // Needed for wxDir #include // Needed for wxZipFSHandler #include // wxFileInputStream #include // Needed for wxZipInputStream #include // Needed for wxZlibInputStream #include // Needed for wxSysErrorMsg #ifdef __WXMAC__ #include // Do_not_auto_remove #endif #include // Needed for std::auto_ptr #include "FileFunctions.h" #include "StringFunctions.h" // // This class assumes that the following line has been executed: // // wxConvFileName = &aMuleConvBrokenFileNames; // // This line is necessary so that wxWidgets handles unix file names correctly. // CDirIterator::CDirIterator(const CPath& dir) : wxDir(dir.GetRaw()) { } CDirIterator::~CDirIterator() { } CPath CDirIterator::GetFirstFile(FileType type, const wxString& mask) { if (!IsOpened()) { return CPath(); } wxString fileName; if (!GetFirst(&fileName, mask, type)) { return CPath(); } return CPath(fileName); } CPath CDirIterator::GetNextFile() { wxString fileName; if (!GetNext(&fileName)) { return CPath(); } return CPath(fileName); } bool CDirIterator::HasSubDirs(const wxString& spec) { // Checking IsOpened() in case we don't have permissions to read that dir. return IsOpened() && wxDir::HasSubDirs(spec); } EFileType GuessFiletype(const wxString& file) { wxFile archive(file, wxFile::read); if (!archive.IsOpened()) { return EFT_Error; } static const uint8 UTF8bom[3] = {0xEF, 0xBB, 0xBF}; uint8 head[10] = {0, 0}; int read = archive.Read(head, std::min(10, archive.Length())); if (read == wxInvalidOffset || read == 0) { return EFT_Unknown; } else if ((head[0] == 'P') && (head[1] == 'K')) { // Zip-archives have a header of "PK". return EFT_Zip; } else if (head[0] == 0x1F && head[1] == 0x8B) { // Gzip-archives have a header of 0x1F8B return EFT_GZip; } else if (head[0] == 0xE0 || head[0] == 0x0E) { // MET files have either of these headers return EFT_Met; } // Check at most the first ten chars, if all are printable, // then we can probably assume it is ascii text-file. for (int i = 0; i < read; ++i) { if (!( isprint(head[i]) || isspace(head[i]) || (i < 3 && head[i] == UTF8bom[i]))) { return EFT_Unknown; } } return EFT_Text; } /** * Replaces the zip-archive with "guarding.p2p" or "ipfilter.dat", * if either of those files are found in the archive. */ bool UnpackZipFile(const wxString& file, const wxChar* files[]) { wxZipFSHandler archive; wxString filename = archive.FindFirst( wxT("file:") + file + wxT("#zip:/*"), wxFILE); wxTempFile target(file); while (!filename.IsEmpty() && !target.Length()) { // Extract the filename part of the URI filename = filename.AfterLast(wxT(':')).Lower(); // We only care about the files specified in the array for (size_t i = 0; files[i] && !target.Length(); ++i) { if (files[i] == filename) { std::auto_ptr entry; wxFFileInputStream fileInputStream(file); wxZipInputStream zip(fileInputStream); while (entry.reset(zip.GetNextEntry()), entry.get() != NULL) { // access meta-data wxString name = entry->GetName(); // read 'zip' to access the entry's data if (name == filename) { char buffer[10240]; while (!zip.Eof()) { zip.Read(buffer, sizeof(buffer)); target.Write(buffer, zip.LastRead()); } break; } } } } filename = archive.FindNext(); } if (target.Length()) { target.Commit(); return true; } return false; } /** * Unpacks a GZip file and replaces the archive. */ bool UnpackGZipFile(const wxString& file) { char buffer[10240]; wxTempFile target(file); bool write = false; #ifdef __WXMAC__ // AddDebugLogLineN( logFileIO, wxT("Reading gzip stream") ); gzFile inputFile = gzopen(filename2char(file), "rb"); if (inputFile != NULL) { write = true; while (int bytesRead = gzread(inputFile, buffer, sizeof(buffer))) { if (bytesRead > 0) { // AddDebugLogLineN(logFileIO, CFormat(wxT("Read %u bytes")) % bytesRead); target.Write(buffer, bytesRead); } else if (bytesRead < 0) { wxString errString; int gzerrnum; const char* gzerrstr = gzerror(inputFile, &gzerrnum); if (gzerrnum == Z_ERRNO) { errString = wxSysErrorMsg(); } else { errString = wxString::FromAscii(gzerrstr); } // AddDebugLogLineN( logFileIO, wxT("Error reading gzip stream (") + errString + wxT(")") ); write = false; break; } } // AddDebugLogLineN( logFileIO, wxT("End reading gzip stream") ); gzclose(inputFile); } else { // AddDebugLogLineN( logFileIO, wxT("Error opening gzip file (") + wxString(wxSysErrorMsg()) + wxT(")") ); } #else { // AddDebugLogLineN( logFileIO, wxT("Reading gzip stream") ); wxFileInputStream source(file); wxZlibInputStream inputStream(source); while (!inputStream.Eof()) { inputStream.Read(buffer, sizeof(buffer)); // AddDebugLogLineN(logFileIO, CFormat(wxT("Read %u bytes")) % inputStream.LastRead()); if (inputStream.LastRead()) { target.Write(buffer, inputStream.LastRead()); } else { break; } }; // AddDebugLogLineN( logFileIO, wxT("End reading gzip stream") ); write = inputStream.IsOk() || inputStream.Eof(); } #endif if (write) { target.Commit(); // AddDebugLogLineN( logFileIO, wxT("Commited gzip stream") ); } return write; } UnpackResult UnpackArchive(const CPath& path, const wxChar* files[]) { const wxString file = path.GetRaw(); // Attempt to discover the filetype and uncompress EFileType type = GuessFiletype(file); switch (type) { case EFT_Zip: if (UnpackZipFile(file, files)) { // Unpack nested archives if needed. return UnpackResult(true, UnpackArchive(path, files).second); } else { return UnpackResult(false, EFT_Error); } case EFT_GZip: if (UnpackGZipFile(file)) { // Unpack nested archives if needed. return UnpackResult(true, UnpackArchive(path, files).second); } else { return UnpackResult(false, EFT_Error); } default: return UnpackResult(false, type); } } // File_checked_for_headers