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 00024 // 3rd party library includes 00025 #include <boost/bind.hpp> 00026 00027 // FIFE includes 00028 // These includes are split up in two parts, separated by one empty line 00029 // First block: files included from the FIFE root src directory 00030 // Second block: files included from the same folder 00031 #include "vfs/raw/rawdata.h" 00032 #include "util/base/exception.h" 00033 #include "util/log/logger.h" 00034 00035 #include "dat2.h" 00036 00037 namespace FIFE { 00038 static Logger _log(LM_FO_LOADERS); 00039 00040 DAT2::DAT2(VFS* vfs, const std::string& file) 00041 : VFSSource(vfs), m_datpath(file), m_data(vfs->open(file)), m_filelist() { 00042 00043 FL_LOG(_log, LMsg("MFFalloutDAT2") 00044 << "loading: " << file 00045 << " filesize: " << m_data->getDataLength()); 00046 00047 m_data->setIndex(m_data->getDataLength() - 8); 00048 uint32_t fileListLength = m_data->read32Little(); 00049 uint32_t archiveSize = m_data->read32Little(); 00050 00051 FL_LOG(_log, LMsg("MFFalloutDAT2") 00052 << "FileListLength: " << fileListLength 00053 << " ArchiveSize: " << archiveSize); 00054 00055 if (archiveSize != m_data->getDataLength()) 00056 throw InvalidFormat("size mismatch"); 00057 00058 m_data->setIndex( archiveSize - fileListLength - 8); 00059 m_filecount = m_data->read32Little(); 00060 m_currentIndex = m_data->getCurrentIndex(); 00061 00062 FL_LOG(_log, LMsg("MFFalloutDAT2 FileCount: ") << m_filecount); 00063 00064 // Do not read the complete file list at startup. 00065 // Instead read a chunk each frame. 00066 m_timer.setInterval(0); 00067 m_timer.setCallback( boost::bind( &DAT2::readFileEntry, this) ); 00068 m_timer.start(); 00069 } 00070 00071 void DAT2::readFileEntry() const { 00072 assert( m_filecount != 0); 00073 00074 // Load more items per call, 00075 // otherwise it takes _ages_ until everything is in. 00076 unsigned int load_per_cycle = 50; 00077 if( load_per_cycle > m_filecount ) 00078 load_per_cycle = m_filecount; 00079 m_filecount -= load_per_cycle; 00080 00081 // Save the old index in an exception save way. 00082 IndexSaver isaver(m_data.get()); 00083 00084 // Move index to file list and read the entries. 00085 m_data->setIndex(m_currentIndex); 00086 RawDataDAT2::s_info info; 00087 while( load_per_cycle-- ) { 00088 uint32_t namelen = m_data->read32Little(); 00089 info.name = fixPath(m_data->readString(namelen)); 00090 00091 info.type = m_data->read8(); 00092 info.unpackedLength = m_data->read32Little(); 00093 info.packedLength = m_data->read32Little(); 00094 info.offset = m_data->read32Little(); 00095 00096 m_filelist.insert(std::make_pair(info.name, info)); 00097 } 00098 m_currentIndex = m_data->getCurrentIndex(); 00099 00100 // Finally log on completion and stop the timer. 00101 if( m_filecount == 0 ) { 00102 FL_LOG(_log, LMsg("MFFalloutDAT2, All file entries in '") << m_datpath << "' loaded."); 00103 m_timer.stop(); 00104 } 00105 } 00106 00107 RawData* DAT2::open(const std::string& file) const { 00108 const RawDataDAT2::s_info& info = getInfo(file); 00109 return new RawData(new RawDataDAT2(getVFS(), m_datpath, info)); 00110 } 00111 00112 bool DAT2::fileExists(const std::string& name) const { 00113 return findFileEntry(name) != m_filelist.end(); 00114 } 00115 00116 const RawDataDAT2::s_info& DAT2::getInfo(const std::string& name) const { 00117 type_filelist::const_iterator i = findFileEntry(name); 00118 if (i == m_filelist.end()) { 00119 throw NotFound(name); 00120 } 00121 return i->second; 00122 } 00123 00124 DAT2::type_filelist::const_iterator DAT2::findFileEntry(const std::string& path) const { 00125 00126 // Either the normalization is bogus, or we have to do 00127 // it here, too. Otherwise we can't load the files returned 00128 // by listFiles. 00129 00130 std::string name = path; 00131 00132 // Normalize the path 00133 if (name.find("./") == 0) { 00134 name.erase(0, 2); 00135 } 00136 00137 type_filelist::const_iterator i = m_filelist.find(name); 00138 00139 // We might have another chance to find the file 00140 // if the number of file entries not zero. 00141 if ( m_filecount && i == m_filelist.end()) { 00142 FL_LOG(_log, LMsg("MFFalloutDAT2") 00143 << "Missing '" << name 00144 << "' in partially(" << m_filecount <<") loaded "<< m_datpath); 00145 while( m_filecount && i == m_filelist.end()) { 00146 readFileEntry(); 00147 i = m_filelist.find(name); 00148 } 00149 } 00150 return i; 00151 } 00152 00153 00154 std::set<std::string> DAT2::listFiles(const std::string& pathstr) const { 00155 return list(pathstr, false); 00156 } 00157 00158 std::set<std::string> DAT2::listDirectories(const std::string& pathstr) const { 00159 return list(pathstr, true); 00160 } 00161 00162 std::set<std::string> DAT2::list(const std::string& pathstr, bool dirs) const { 00163 std::set<std::string> list; 00164 std::string path = pathstr; 00165 00166 // Force loading the complete file entries 00167 // This is a costly operation... right after startup. 00168 // Later this should do nothing. 00169 while( m_filecount ) { 00170 readFileEntry(); 00171 } 00172 00173 // Normalize the path 00174 if (path.find("./") == 0) { 00175 path.erase(0, 2); 00176 } 00177 00178 int lastIndex = path.size() - 1; 00179 if ((lastIndex != -1) && path[lastIndex] != '/') { 00180 path += '/'; 00181 } 00182 00183 type_filelist::const_iterator end = m_filelist.end(); 00184 for (type_filelist::const_iterator i = m_filelist.begin(); i != end; ++i) { 00185 const std::string& file = i->first; 00186 if (file.find(path) == 0) { 00187 std::string cleanedfile = file.substr(path.size(), file.size()); // strip the pathstr 00188 bool isdir = cleanedfile.find('/') != std::string::npos; // if we still have a / it's a subdir 00189 00190 if (isdir) { 00191 cleanedfile = cleanedfile.substr(0, cleanedfile.find('/')); 00192 if (cleanedfile.find('/') != cleanedfile.rfind('/')) { 00193 // check if this is a direct subdir 00194 continue; 00195 } 00196 } 00197 00198 if (isdir == dirs) { 00199 list.insert(cleanedfile); 00200 } 00201 } 00202 } 00203 00204 return list; 00205 } 00206 } // FIFE