dat2.cpp
00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <boost/bind.hpp>
00026
00027
00028
00029
00030
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
00065
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
00075
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
00082 IndexSaver isaver(m_data.get());
00083
00084
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
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
00127
00128
00129
00130 std::string name = path;
00131
00132
00133 if (name.find("./") == 0) {
00134 name.erase(0, 2);
00135 }
00136
00137 type_filelist::const_iterator i = m_filelist.find(name);
00138
00139
00140
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
00167
00168
00169 while( m_filecount ) {
00170 readFileEntry();
00171 }
00172
00173
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());
00188 bool isdir = cleanedfile.find('/') != std::string::npos;
00189
00190 if (isdir) {
00191 cleanedfile = cleanedfile.substr(0, cleanedfile.find('/'));
00192 if (cleanedfile.find('/') != cleanedfile.rfind('/')) {
00193
00194 continue;
00195 }
00196 }
00197
00198 if (isdir == dirs) {
00199 list.insert(cleanedfile);
00200 }
00201 }
00202 }
00203
00204 return list;
00205 }
00206 }