FIFE 2008.0
|
00001 /*************************************************************************** 00002 * Copyright (C) 2005-2008 by the FIFE team * 00003 * http://www.fifengine.de * 00004 * This file is part of FIFE. * 00005 * * 00006 * FIFE is free software; you can redistribute it and/or * 00007 * modify it under the terms of the GNU Lesser General Public * 00008 * License as published by the Free Software Foundation; either * 00009 * version 2.1 of the License, or (at your option) any later version. * 00010 * * 00011 * This library is distributed in the hope that it will be useful, * 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 00014 * Lesser General Public License for more details. * 00015 * * 00016 * You should have received a copy of the GNU Lesser General Public * 00017 * License along with this library; if not, write to the * 00018 * Free Software Foundation, Inc., * 00019 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * 00020 ***************************************************************************/ 00021 00022 // Standard C++ library includes 00023 #include <algorithm> 00024 #include <list> 00025 00026 // 3rd party library includes 00027 #include "zlib.h" 00028 #include <boost/scoped_array.hpp> 00029 00030 // FIFE includes 00031 // These includes are split up in two parts, separated by one empty line 00032 // First block: files included from the FIFE root src directory 00033 // Second block: files included from the same folder 00034 #include "util/base/exception.h" 00035 #include "vfs/raw/rawdata.h" 00036 #include "util/log/logger.h" 00037 00038 #include "zipsource.h" 00039 #include "zipfilesource.h" 00040 00041 namespace FIFE { 00042 00043 static const uint32_t LF_HEADER = 0x04034b50; 00044 static const uint32_t DE_HEADER = 0x08064b50; 00045 static const uint32_t CF_HEADER = 0x02014b50; 00046 00047 static Logger _log(LM_LOADERS); 00048 00049 ZipSource::ZipSource(VFS* vfs, const std::string& zip_file) : VFSSource(vfs), m_zipfile(vfs->open(zip_file)) { 00050 readIndex(); 00051 } 00052 00053 ZipSource::~ZipSource() { 00054 delete m_zipfile; 00055 } 00056 00057 bool ZipSource::fileExists(const std::string& file) const { 00058 return m_files.find(file) != m_files.end(); 00059 } 00060 00061 RawData* ZipSource::open(const std::string& path) const { 00062 type_files::const_iterator i = m_files.find(path); 00063 assert(i != m_files.end()); 00064 const s_data& info = i->second; 00065 00066 m_zipfile->setIndex(info.offset); 00067 uint8_t* data = new uint8_t[info.size_real]; // beware of me - one day i WILL cause memory leaks 00068 if (info.comp == 8) { // compressed using deflate 00069 FL_DBG(_log, LMsg("trying to uncompress file ") << path << " (compressed with method " << info.comp << ")"); 00070 boost::scoped_array<uint8_t> compdata(new uint8_t[info.size_comp]); 00071 m_zipfile->readInto(compdata.get(), info.size_comp); 00072 00073 z_stream zstream; 00074 zstream.next_in = compdata.get(); 00075 zstream.avail_in = info.size_comp; 00076 zstream.zalloc = Z_NULL; 00077 zstream.zfree = Z_NULL; 00078 zstream.opaque = Z_NULL; 00079 zstream.next_out = data; 00080 zstream.avail_out = info.size_real; 00081 00082 if (inflateInit2(&zstream, -15) != Z_OK) { 00083 FL_ERR(_log, LMsg("inflateInit2 failed")); 00084 delete[] data; 00085 return 0; 00086 } 00087 00088 int err = inflate(&zstream, Z_FINISH); 00089 if (err != Z_STREAM_END) { 00090 if (zstream.msg) { 00091 FL_ERR(_log, LMsg("inflate failed: ") << zstream.msg); 00092 } else { 00093 FL_ERR(_log, LMsg("inflate failed without msg, err: ") << err); 00094 } 00095 00096 inflateEnd(&zstream); 00097 delete[] data; 00098 return 0; 00099 } 00100 00101 inflateEnd(&zstream); 00102 } else if (info.comp == 0) { // uncompressed 00103 m_zipfile->readInto(data, info.size_real); 00104 } else { 00105 FL_ERR(_log, LMsg("unsupported compression")); 00106 return 0; 00107 } 00108 00109 return new RawData(new ZipFileSource(data, info.size_real)); 00110 } 00111 00112 void ZipSource::readIndex() { 00113 m_zipfile->setIndex(0); 00114 m_files.clear(); 00115 00116 while (!readFileToIndex()) {} 00117 } 00118 00119 bool ZipSource::readFileToIndex() { 00120 uint32_t header = m_zipfile->read32Little(); 00121 if (header == DE_HEADER || header == CF_HEADER) { // decryption header or central directory header - we are finished 00122 return true; 00123 } 00124 00125 uint16_t vneeded = m_zipfile->read16Little(); 00126 uint16_t gflags = m_zipfile->read16Little(); 00127 uint16_t comp = m_zipfile->read16Little(); 00128 uint16_t lmodtime = m_zipfile->read16Little(); 00129 uint16_t lmoddate = m_zipfile->read16Little(); 00130 uint32_t crc = m_zipfile->read32Little(); 00131 uint32_t compsize = m_zipfile->read32Little(); 00132 uint32_t realsize = m_zipfile->read32Little(); 00133 uint16_t fnamelen = m_zipfile->read16Little(); 00134 uint16_t extralen = m_zipfile->read16Little(); 00135 00136 if (header != LF_HEADER) { 00137 FL_ERR(_log, LMsg("invalid local file header: ") << header); 00138 return true; 00139 } 00140 00141 if (vneeded > 20) { 00142 FL_ERR(_log, LMsg("only zip version 2 is supported, required: ") << vneeded); 00143 return true; 00144 } 00145 00146 std::string filename = m_zipfile->readString(fnamelen); 00147 m_zipfile->moveIndex(extralen); 00148 unsigned int offset = m_zipfile->getCurrentIndex(); 00149 FL_DBG(_log, LMsg("found file: ") << filename << " (" << compsize << "/" << realsize << ") on offset " << offset); 00150 00151 m_zipfile->moveIndex(compsize); 00152 if (gflags & (0x01 << 3)) { 00153 crc = m_zipfile->read32Little(); 00154 compsize = m_zipfile->read32Little(); 00155 realsize = m_zipfile->read32Little(); 00156 } 00157 00158 if (lmodtime || lmoddate) {} // shut up the compiler (warnings of unused variables) 00159 00160 s_data data; 00161 data.comp = comp; 00162 data.size_real = realsize; 00163 data.size_comp = compsize; 00164 data.offset = offset; 00165 data.path = filename; 00166 data.crc32 = crc; 00167 00168 m_files[filename] = data; 00169 return false; 00170 } 00171 00172 00173 // FIXME: quick&very dirty.. 00174 std::set<std::string> ZipSource::listFiles(const std::string& path) const { 00175 std::set<std::string> result; 00176 00177 std::string fixedPath = fixPath(path); 00178 int path_len = path.length(); 00179 if (fixedPath[path_len - 1] != '/') { 00180 fixedPath += '/'; 00181 path_len++; 00182 } 00183 00184 type_files::const_iterator end = m_files.end(); 00185 for (type_files::const_iterator i = m_files.begin(); i != end; ++i) { 00186 std::string name = i->first; 00187 int len = name.length(); 00188 if (len && name.find(fixedPath) == 0 && name[len - 1] != '/') { 00189 name = name.substr(path_len); 00190 size_t pos = name.find("/"); 00191 if (pos != std::string::npos) 00192 continue; 00193 00194 result.insert(name); 00195 } 00196 } 00197 00198 return result; 00199 } 00200 00201 // FIXME: quick&very dirty.. 00202 std::set<std::string> ZipSource::listDirectories(const std::string& path) const { 00203 std::set<std::string> result; 00204 00205 std::string fixedPath = fixPath(path); 00206 int path_len = path.length(); 00207 if (fixedPath[path_len - 1] != '/') { 00208 fixedPath += '/'; 00209 path_len++; 00210 } 00211 00212 type_files::const_iterator end = m_files.end(); 00213 for (type_files::const_iterator i = m_files.begin(); i != end; ++i) { 00214 std::string name = i->first; 00215 int len = name.length(); 00216 if (len && name.find(fixedPath) == 0 && name[len - 1] == '/' && len > path_len) { 00217 name = name.substr(path_len); 00218 size_t pos = name.find("/"); 00219 if (pos != std::string::npos) { 00220 name = name.substr(0, pos); 00221 } 00222 result.insert(name); 00223 } 00224 } 00225 00226 return result; 00227 } 00228 }