comparison engine/core/vfs/dat/dat2.cpp @ 0:4a0efb7baf70

* Datasets becomes the new trunk and retires after that :-)
author mvbarracuda@33b003aa-7bff-0310-803a-e67f0ece8222
date Sun, 29 Jun 2008 18:44:17 +0000
parents
children 90005975cdbb
comparison
equal deleted inserted replaced
-1:000000000000 0:4a0efb7baf70
1 /***************************************************************************
2 * Copyright (C) 2005-2008 by the FIFE team *
3 * http://www.fifengine.de *
4 * This file is part of FIFE. *
5 * *
6 * FIFE is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 2 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the *
18 * Free Software Foundation, Inc., *
19 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA *
20 ***************************************************************************/
21
22 // Standard C++ library includes
23
24 // 3rd party library includes
25 #include <boost/bind.hpp>
26
27 // FIFE includes
28 // These includes are split up in two parts, separated by one empty line
29 // First block: files included from the FIFE root src directory
30 // Second block: files included from the same folder
31 #include "vfs/raw/rawdata.h"
32 #include "util/base/exception.h"
33 #include "util/log/logger.h"
34
35 #include "dat2.h"
36
37 namespace FIFE {
38 static Logger _log(LM_FO_LOADERS);
39
40 DAT2::DAT2(VFS* vfs, const std::string& file)
41 : VFSSource(vfs), m_datpath(file), m_data(vfs->open(file)), m_filelist() {
42
43 FL_LOG(_log, LMsg("MFFalloutDAT2")
44 << "loading: " << file
45 << " filesize: " << m_data->getDataLength());
46
47 m_data->setIndex(m_data->getDataLength() - 8);
48 uint32_t fileListLength = m_data->read32Little();
49 uint32_t archiveSize = m_data->read32Little();
50
51 FL_LOG(_log, LMsg("MFFalloutDAT2")
52 << "FileListLength: " << fileListLength
53 << " ArchiveSize: " << archiveSize);
54
55 if (archiveSize != m_data->getDataLength())
56 throw InvalidFormat("size mismatch");
57
58 m_data->setIndex( archiveSize - fileListLength - 8);
59 m_filecount = m_data->read32Little();
60 m_currentIndex = m_data->getCurrentIndex();
61
62 FL_LOG(_log, LMsg("MFFalloutDAT2 FileCount: ") << m_filecount);
63
64 // Do not read the complete file list at startup.
65 // Instead read a chunk each frame.
66 m_timer.setInterval(0);
67 m_timer.setCallback( boost::bind( &DAT2::readFileEntry, this) );
68 m_timer.start();
69 }
70
71 void DAT2::readFileEntry() const {
72 assert( m_filecount != 0);
73
74 // Load more items per call,
75 // otherwise it takes _ages_ until everything is in.
76 unsigned int load_per_cycle = 50;
77 if( load_per_cycle > m_filecount )
78 load_per_cycle = m_filecount;
79 m_filecount -= load_per_cycle;
80
81 // Save the old index in an exception save way.
82 IndexSaver isaver(m_data.get());
83
84 // Move index to file list and read the entries.
85 m_data->setIndex(m_currentIndex);
86 RawDataDAT2::s_info info;
87 while( load_per_cycle-- ) {
88 uint32_t namelen = m_data->read32Little();
89 info.name = fixPath(m_data->readString(namelen));
90
91 info.type = m_data->read8();
92 info.unpackedLength = m_data->read32Little();
93 info.packedLength = m_data->read32Little();
94 info.offset = m_data->read32Little();
95
96 m_filelist.insert(std::make_pair(info.name, info));
97 }
98 m_currentIndex = m_data->getCurrentIndex();
99
100 // Finally log on completion and stop the timer.
101 if( m_filecount == 0 ) {
102 FL_LOG(_log, LMsg("MFFalloutDAT2, All file entries in '") << m_datpath << "' loaded.");
103 m_timer.stop();
104 }
105 }
106
107 RawData* DAT2::open(const std::string& file) const {
108 const RawDataDAT2::s_info& info = getInfo(file);
109 return new RawData(new RawDataDAT2(getVFS(), m_datpath, info));
110 }
111
112 bool DAT2::fileExists(const std::string& name) const {
113 return findFileEntry(name) != m_filelist.end();
114 }
115
116 const RawDataDAT2::s_info& DAT2::getInfo(const std::string& name) const {
117 type_filelist::const_iterator i = findFileEntry(name);
118 if (i == m_filelist.end()) {
119 throw NotFound(name);
120 }
121 return i->second;
122 }
123
124 DAT2::type_filelist::const_iterator DAT2::findFileEntry(const std::string& path) const {
125
126 // Either the normalization is bogus, or we have to do
127 // it here, too. Otherwise we can't load the files returned
128 // by listFiles.
129
130 std::string name = path;
131
132 // Normalize the path
133 if (name.find("./") == 0) {
134 name.erase(0, 2);
135 }
136
137 type_filelist::const_iterator i = m_filelist.find(name);
138
139 // We might have another chance to find the file
140 // if the number of file entries not zero.
141 if ( m_filecount && i == m_filelist.end()) {
142 FL_LOG(_log, LMsg("MFFalloutDAT2")
143 << "Missing '" << name
144 << "' in partially(" << m_filecount <<") loaded "<< m_datpath);
145 while( m_filecount && i == m_filelist.end()) {
146 readFileEntry();
147 i = m_filelist.find(name);
148 }
149 }
150 return i;
151 }
152
153
154 std::set<std::string> DAT2::listFiles(const std::string& pathstr) const {
155 return list(pathstr, false);
156 }
157
158 std::set<std::string> DAT2::listDirectories(const std::string& pathstr) const {
159 return list(pathstr, true);
160 }
161
162 std::set<std::string> DAT2::list(const std::string& pathstr, bool dirs) const {
163 std::set<std::string> list;
164 std::string path = pathstr;
165
166 // Force loading the complete file entries
167 // This is a costly operation... right after startup.
168 // Later this should do nothing.
169 while( m_filecount ) {
170 readFileEntry();
171 }
172
173 // Normalize the path
174 if (path.find("./") == 0) {
175 path.erase(0, 2);
176 }
177
178 int lastIndex = path.size() - 1;
179 if ((lastIndex != -1) && path[lastIndex] != '/') {
180 path += '/';
181 }
182
183 type_filelist::const_iterator end = m_filelist.end();
184 for (type_filelist::const_iterator i = m_filelist.begin(); i != end; ++i) {
185 const std::string& file = i->first;
186 if (file.find(path) == 0) {
187 std::string cleanedfile = file.substr(path.size(), file.size()); // strip the pathstr
188 bool isdir = cleanedfile.find('/') != std::string::npos; // if we still have a / it's a subdir
189
190 if (isdir) {
191 cleanedfile = cleanedfile.substr(0, cleanedfile.find('/'));
192 if (cleanedfile.find('/') != cleanedfile.rfind('/')) {
193 // check if this is a direct subdir
194 continue;
195 }
196 }
197
198 if (isdir == dirs) {
199 list.insert(cleanedfile);
200 }
201 }
202 }
203
204 return list;
205 }
206 } // FIFE