Mercurial > fife-parpg
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 |